asmith updated this revision to Diff 155904.
asmith added a comment.
Adding missing inputs
https://reviews.llvm.org/D49410
Files:
lit/SymbolFile/PDB/Inputs/ClassLayoutTest.cpp
lit/SymbolFile/PDB/Inputs/PointerTypeTest.cpp
lit/SymbolFile/PDB/class-layout.test
lit/SymbolFile/PDB/pointers.test
source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
source/Plugins/SymbolFile/PDB/PDBASTParser.h
source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
Index: source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
===================================================================
--- source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -45,7 +45,7 @@
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
-#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" // For IsCPPMangledName
#include "Plugins/SymbolFile/PDB/PDBASTParser.h"
#include "Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h"
@@ -557,9 +557,37 @@
if (pdb_type == nullptr)
return nullptr;
+ // Parse base classes and nested UDTs first.
+ switch (pdb_type->getSymTag()) {
+ case PDB_SymType::UDT:
+ case PDB_SymType::BaseClass: {
+ if (auto base_classes =
+ pdb_type->findAllChildren<PDBSymbolTypeBaseClass>()) {
+ while (auto base_class = base_classes->getNext())
+ ResolveTypeUID(base_class->getSymIndexId());
+ }
+ if (pdb_type->getRawSymbol().hasNestedTypes()) {
+ if (auto nested_udts = pdb_type->findAllChildren<PDBSymbolTypeUDT>()) {
+ while (auto nested = nested_udts->getNext())
+ ResolveTypeUID(nested->getSymIndexId());
+ }
+ }
+ } break;
+ default:
+ break;
+ }
+
lldb::TypeSP result = pdb->CreateLLDBTypeFromPDBType(*pdb_type);
if (result) {
m_types.insert(std::make_pair(type_uid, result));
+
+ // Complete the type for UDT & BaseClass symbol immediately. BaseClass is
+ // parsed by its type which might have been completed before. Make sure we
+ // only do this once.
+ if (result->GetID() == type_uid) {
+ pdb->CompleteRecordTypeForPDBSymbol(*pdb_type, result);
+ }
+
auto type_list = GetTypeList();
if (type_list)
type_list->Insert(result);
Index: source/Plugins/SymbolFile/PDB/PDBASTParser.h
===================================================================
--- source/Plugins/SymbolFile/PDB/PDBASTParser.h
+++ source/Plugins/SymbolFile/PDB/PDBASTParser.h
@@ -31,6 +31,7 @@
class PDBSymbol;
class PDBSymbolData;
class PDBSymbolTypeBuiltin;
+class PDBSymbolTypeUDT;
} // namespace pdb
} // namespace llvm
@@ -41,10 +42,17 @@
lldb::TypeSP CreateLLDBTypeFromPDBType(const llvm::pdb::PDBSymbol &type);
+ bool CompleteRecordTypeForPDBSymbol(const llvm::pdb::PDBSymbol &pdb_symbol,
+ lldb::TypeSP type_sp);
+
private:
bool AddEnumValue(lldb_private::CompilerType enum_type,
const llvm::pdb::PDBSymbolData &data) const;
+ bool
+ AddMembersToRecordType(const lldb_private::CompilerType &udt_compiler_type,
+ const llvm::pdb::PDBSymbolTypeUDT &pdb_udt);
+
lldb_private::ClangASTContext &m_ast;
lldb_private::ClangASTImporter m_ast_importer;
};
Index: source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
===================================================================
--- source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
+++ source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/DeclCXX.h"
#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.h" // For ClangASTMetadata
#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/Declaration.h"
#include "lldb/Symbol/SymbolFile.h"
@@ -175,6 +176,28 @@
return compiler_type.GetTypeName();
}
+AccessType TranslateMemberAccess(PDB_MemberAccess access) {
+ if (access == PDB_MemberAccess::Public)
+ return lldb::eAccessPublic;
+ if (access == PDB_MemberAccess::Private)
+ return lldb::eAccessPrivate;
+ if (access == PDB_MemberAccess::Protected)
+ return lldb::eAccessProtected;
+ return lldb::eAccessNone;
+}
+
+AccessType GetDefaultAccessibilityForUdtKind(PDB_UdtType udt_kind) {
+ if (udt_kind == PDB_UdtType::Class)
+ return lldb::eAccessPrivate;
+ if (udt_kind == PDB_UdtType::Struct)
+ return lldb::eAccessPublic;
+ if (udt_kind == PDB_UdtType::Union)
+ return lldb::eAccessPublic;
+ if (udt_kind == PDB_UdtType::Interface)
+ return lldb::eAccessPrivate;
+ return lldb::eAccessNone;
+}
+
bool GetDeclarationForSymbol(const PDBSymbol &symbol, Declaration &decl) {
auto &raw_sym = symbol.getRawSymbol();
auto first_line_up = raw_sym.getSrcLineOnTypeDefn();
@@ -216,29 +239,84 @@
Declaration decl;
switch (type.getSymTag()) {
+ case PDB_SymType::BaseClass: {
+ auto ty =
+ m_ast.GetSymbolFile()->ResolveTypeUID(type.getRawSymbol().getTypeId());
+ return ty ? ty->shared_from_this() : nullptr;
+ } break;
case PDB_SymType::UDT: {
auto udt = llvm::dyn_cast<PDBSymbolTypeUDT>(&type);
assert(udt);
- AccessType access = lldb::eAccessPublic;
+
+ // Note that, unnamed UDT being typedef-ed is generated as a UDT symbol
+ // other than a Typedef symbol in PDB. For example,
+ // typedef union { short Row; short Col; } Union;
+ // is generated as a named UDT in PDB:
+ // union Union { short Row; short Col; }
+ // Such symbols will be handled here.
+
+ // Some UDT with trival ctor has zero length. Just ignore.
+ if (udt->getLength() == 0)
+ return nullptr;
+
+ // Ignore unnamed-tag UDTs.
+ if (udt->getName().empty())
+ return nullptr;
+
PDB_UdtType udt_kind = udt->getUdtKind();
auto tag_type_kind = TranslateUdtKind(udt_kind);
- if (tag_type_kind == -1)
- return nullptr;
+ assert(tag_type_kind != -1);
+
+ AccessType access = TranslateMemberAccess(udt->getAccess());
+ if (access == lldb::eAccessNone && udt->isNested() &&
+ udt->getClassParent()) {
+ access = GetDefaultAccessibilityForUdtKind(udt_kind);
+ }
- if (udt_kind == PDB_UdtType::Class)
- access = lldb::eAccessPrivate;
+ ClangASTMetadata metadata;
+ metadata.SetUserID(type.getSymIndexId());
+ metadata.SetIsDynamicCXXType(false);
+
+ // We defer resolving UDTs since some symbol like doubly linked list could
+ // result in endless recursion.
+ Type::ResolveStateTag type_resolve_state_tag = Type::eResolveStateForward;
CompilerType clang_type = m_ast.CreateRecordType(
tu_decl_ctx, access, udt->getName().c_str(), tag_type_kind,
- lldb::eLanguageTypeC_plus_plus, nullptr);
+ lldb::eLanguageTypeC_plus_plus, &metadata);
+ assert(clang_type.IsValid());
+
+ m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), false);
+
+ if (udt->isConstType())
+ clang_type = clang_type.AddConstModifier();
+
+ if (udt->isVolatileType())
+ clang_type = clang_type.AddVolatileModifier();
+
+ auto children = udt->findAllChildren();
+ if (!children || children->getChildCount() == 0) {
+ // PDB does not have symbol of forwarder. We assume we get an udt w/o any
+ // fields. Just complete it at this point.
+ if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) {
+ ClangASTContext::CompleteTagDeclarationDefinition(clang_type);
+ type_resolve_state_tag = lldb_private::Type::eResolveStateFull;
+ } else {
+ // We are not able to complete udt type.
+ return nullptr;
+ }
+ }
m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true);
- return std::make_shared<lldb_private::Type>(
+ GetDeclarationForSymbol(type, decl);
+ auto type_sp = std::make_shared<lldb_private::Type>(
type.getSymIndexId(), m_ast.GetSymbolFile(),
ConstString(udt->getName()), udt->getLength(), nullptr,
LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, clang_type,
- lldb_private::Type::eResolveStateForward);
+ type_resolve_state_tag);
+
+ return type_sp;
} break;
case PDB_SymType::Enum: {
auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(&type);
@@ -441,6 +519,26 @@
if (!pointee_type)
return nullptr;
+ if (pointer_type->isPointerToDataMember() ||
+ pointer_type->isPointerToMemberFunction()) {
+ auto class_parent_uid = pointer_type->getRawSymbol().getClassParentId();
+ auto class_parent_type =
+ m_ast.GetSymbolFile()->ResolveTypeUID(class_parent_uid);
+ assert(class_parent_type);
+
+ CompilerType pointer_ast_type;
+ pointer_ast_type = ClangASTContext::CreateMemberPointerType(
+ class_parent_type->GetLayoutCompilerType(),
+ pointee_type->GetForwardCompilerType());
+ assert(pointer_ast_type);
+
+ return std::make_shared<lldb_private::Type>(
+ pointer_type->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(),
+ pointer_type->getLength(), nullptr, LLDB_INVALID_UID,
+ lldb_private::Type::eEncodingIsUID, decl, pointer_ast_type,
+ lldb_private::Type::eResolveStateForward);
+ }
+
CompilerType pointer_ast_type;
pointer_ast_type = pointee_type->GetFullCompilerType();
if (pointer_type->isReference())
@@ -513,3 +611,165 @@
enum_type.GetOpaqueQualType(), underlying_type, decl, name.c_str(),
raw_value, byte_size * 8);
}
+
+bool PDBASTParser::AddMembersToRecordType(const CompilerType &udt_compiler_type,
+ const PDBSymbolTypeUDT &pdb_udt) {
+ auto members = pdb_udt.findAllChildren();
+ if (!members)
+ return false;
+
+ llvm::SmallVector<clang::CXXBaseSpecifier *, 8> base_classes;
+
+ while (auto member = members->getNext()) {
+ if (auto pdb_data = llvm::dyn_cast<PDBSymbolData>(member.get())) {
+ if (pdb_data->isCompilerGenerated())
+ continue;
+ auto data_type = pdb_data->getType();
+ if (!data_type)
+ continue;
+ auto type_sp =
+ m_ast.GetSymbolFile()->ResolveTypeUID(data_type->getSymIndexId());
+ if (!type_sp)
+ continue;
+
+ auto access = TranslateMemberAccess(pdb_data->getAccess());
+ assert(access != lldb::eAccessNone);
+
+ auto loc_type = pdb_data->getLocationType();
+ uint32_t bitfield_bit_size = 0;
+ if (loc_type == PDB_LocType::BitField)
+ bitfield_bit_size = pdb_data->getLength();
+
+ auto member_name = pdb_data->getName();
+ auto data_kind = pdb_data->getDataKind();
+ if (data_kind == PDB_DataKind::Member) {
+ auto member_ast_type = type_sp->GetLayoutCompilerType();
+ if (!member_ast_type.IsCompleteType())
+ member_ast_type.GetCompleteType();
+ // CXX class type member must be parsed and complete ahead.
+ if (ClangASTContext::IsCXXClassType(member_ast_type) &&
+ member_ast_type.GetCompleteType() == false) {
+ if (ClangASTContext::StartTagDeclarationDefinition(member_ast_type)) {
+ ClangASTContext::CompleteTagDeclarationDefinition(member_ast_type);
+ } else {
+ // We are not able to start definition.
+ continue;
+ }
+ }
+ assert(member_ast_type.IsCompleteType());
+
+ if (!member_name.empty()) {
+ ClangASTContext::AddFieldToRecordType(
+ udt_compiler_type, member_name.c_str(), member_ast_type, access,
+ bitfield_bit_size);
+ } else {
+ // For now PDB does not generate symbol for unnamed bitfiled. We
+ // handle it anyway.
+ assert(pdb_data->getSymTag() == PDB_SymType::BuiltinType);
+ ClangASTContext::AddFieldToRecordType(udt_compiler_type, NULL,
+ member_ast_type, access,
+ pdb_data->getLength());
+ }
+ } else if (data_kind == PDB_DataKind::StaticMember) {
+ ClangASTContext::AddVariableToRecordType(
+ udt_compiler_type, member_name.c_str(),
+ type_sp->GetLayoutCompilerType(), access);
+ } else {
+ llvm_unreachable("Unhandled data kind!");
+ }
+ } else if (auto pdb_base_class =
+ llvm::dyn_cast<PDBSymbolTypeBaseClass>(member.get())) {
+ auto base_class_type_sp = m_ast.GetSymbolFile()->ResolveTypeUID(
+ pdb_base_class->getSymIndexId());
+ if (!base_class_type_sp)
+ continue;
+
+ // Base class type must be parsed and complete ahead.
+ auto base_ast_type = base_class_type_sp->GetFullCompilerType();
+ assert(base_ast_type && base_ast_type.IsCompleteType());
+
+ auto access = TranslateMemberAccess(pdb_base_class->getAccess());
+ assert(access != lldb::eAccessNone);
+
+ auto base_spec = m_ast.CreateBaseClassSpecifier(
+ base_ast_type.GetOpaqueQualType(), access,
+ pdb_base_class->isVirtualBaseClass(), /*base_of_class*/ true);
+ base_classes.push_back(base_spec);
+
+ } else if (auto pdb_func = llvm::dyn_cast<PDBSymbolFunc>(member.get())) {
+ auto method_type_sp =
+ m_ast.GetSymbolFile()->ResolveTypeUID(pdb_func->getSymIndexId());
+ // MSVC specific __vecDelDtor.
+ if (!method_type_sp)
+ break;
+
+ auto method_ast_type = method_type_sp->GetFullCompilerType();
+ assert(method_ast_type.IsCompleteType());
+ // TODO: get mangled name for the method.
+ m_ast.AddMethodToCXXRecordType(
+ udt_compiler_type.GetOpaqueQualType(), pdb_func->getName().c_str(),
+ /*mangled_name*/ nullptr, method_ast_type,
+ TranslateMemberAccess(pdb_func->getAccess()), pdb_func->isVirtual(),
+ pdb_func->isStatic(), pdb_func->hasInlineAttribute(),
+ /*is_explicit*/ false, // FIXME: Need this field in CodeView.
+ /*is_attr_used*/ false,
+ /*is_artificial*/ pdb_func->isCompilerGenerated());
+
+ } else if (auto pdb_nested_udt =
+ llvm::dyn_cast<PDBSymbolTypeUDT>(member.get())) {
+ // TODO: to handle nested UDTs, need to get correct decl context for UDT.
+ } else {
+ // Unhandled nested types: typedef etc.
+ }
+ }
+
+ if (!base_classes.empty()) {
+ bool result = m_ast.SetBaseClassesForClassType(
+ udt_compiler_type.GetOpaqueQualType(), &base_classes.front(),
+ base_classes.size());
+ assert(result);
+ ClangASTContext::DeleteBaseClassSpecifiers(&base_classes.front(),
+ base_classes.size());
+ }
+
+ return true;
+}
+
+bool PDBASTParser::CompleteRecordTypeForPDBSymbol(const PDBSymbol &pdb_symbol,
+ TypeSP type_sp) {
+ switch (pdb_symbol.getSymTag()) {
+ case PDB_SymType::BaseClass:
+ case PDB_SymType::UDT: {
+ auto clang_type = type_sp->GetForwardCompilerType();
+ const PDBSymbolTypeUDT *pdb_udt;
+ if (auto base_class = llvm::dyn_cast<PDBSymbolTypeBaseClass>(&pdb_symbol))
+ pdb_udt =
+ llvm::dyn_cast<PDBSymbolTypeUDT>(base_class->getType().release());
+ else
+ pdb_udt = llvm::dyn_cast<PDBSymbolTypeUDT>(&pdb_symbol);
+ assert(pdb_udt);
+
+ if (!ClangASTContext::StartTagDeclarationDefinition(clang_type)) {
+ // We are not able to start definition.
+ return false;
+ }
+
+ AddMembersToRecordType(clang_type, *pdb_udt);
+
+ ClangASTContext::BuildIndirectFields(clang_type);
+ ClangASTContext::CompleteTagDeclarationDefinition(clang_type);
+ // Reset the type with a fully resolved compiler type.
+ type_sp.reset(new Type(type_sp->GetID(), m_ast.GetSymbolFile(),
+ type_sp->GetName(), type_sp->GetByteSize(), nullptr,
+ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID,
+ type_sp->GetDeclaration(), clang_type,
+ lldb_private::Type::eResolveStateFull));
+ return true;
+ } break;
+
+ default:
+ return false;
+ }
+
+ return false;
+}
\ No newline at end of file
Index: lit/SymbolFile/PDB/pointers.test
===================================================================
--- /dev/null
+++ lit/SymbolFile/PDB/pointers.test
@@ -0,0 +1,33 @@
+REQUIRES: windows
+RUN: clang-cl -m32 /Z7 /c /GS- %S/Inputs/PointerTypeTest.cpp /o %T/PointerTypeTest.cpp.obj
+RUN: link %T/PointerTypeTest.cpp.obj /DEBUG /nodefaultlib /ENTRY:main /OUT:%T/PointerTypeTest.cpp.exe
+RUN: lldb-test symbols %T/PointerTypeTest.cpp.exe | FileCheck %s
+
+CHECK: Module [[MOD:.*]]
+CHECK-DAG: name = "main::ST::f"
+CHECK-SAME: decl = PointerTypeTest.cpp:10
+CHECK-SAME: compiler_type = {{.*}} int (int)
+
+CHECK-DAG: name = "main::ST", size = 4, decl = PointerTypeTest.cpp:8, compiler_type = {{.*}} struct main::ST {
+CHECK-NEXT: int a;
+CHECK-NEXT: int {{.*}}f(int);
+CHECK-NEXT:}
+
+CHECK-DAG: {{^[0-9A-F]+}}: CompileUnit{{[{]0x[0-9a-f]+[}]}}, language = "c++", file = '{{.*}}\PointerTypeTest.cpp'
+CHECK-DAG: Function{[[FID1:.*]]}, mangled = _main
+CHECK-NEXT: Block{[[FID1]]}
+CHECK-DAG: Variable{{.*}}, name = "array_pointer"
+CHECK-SAME: (int (*)[2][4]), scope = local
+CHECK-DAG: Variable{{.*}}, name = "p_int"
+CHECK-SAME: (int *), scope = local
+CHECK-DAG: Variable{{.*}}, name = "p_member_field"
+CHECK-SAME: (int main::ST::*), scope = local
+CHECK-DAG: Variable{{.*}}, name = "p_member_method"
+CHECK-SAME: (int (main::ST::*)(int)), scope = local
+
+CHECK-DAG: Function{[[FID2:.*]]}, demangled = {{.*}}f(int)
+CHECK-NEXT: Block{[[FID2]]}
+CHECK-DAG: Variable{{.*}}, name = "this"
+CHECK-SAME: (main::ST *), scope = parameter, artificial
+CHECK-DAG: Variable{{.*}}, name = "x"
+CHECK-SAME: (int), scope = parameter, decl = PointerTypeTest.cpp:10
Index: lit/SymbolFile/PDB/class-layout.test
===================================================================
--- /dev/null
+++ lit/SymbolFile/PDB/class-layout.test
@@ -0,0 +1,83 @@
+REQUIRES: windows
+RUN: clang-cl -m32 /Z7 /c /GS- %S/Inputs/ClassLayoutTest.cpp /o %T/ClassLayoutTest.cpp.obj
+RUN: link %T/ClassLayoutTest.cpp.obj /DEBUG /nodefaultlib /ENTRY:main /OUT:%T/ClassLayoutTest.cpp.exe
+RUN: lldb-test symbols %T/ClassLayoutTest.cpp.exe | FileCheck %s
+
+CHECK: Module [[MOD:.*]]
+CHECK-DAG: {{^[0-9A-F]+}}: SymbolVendor ([[MOD]])
+CHECK-DAG: name = "Enum", size = 4, decl = ClassLayoutTest.cpp:4
+CHECK-SAME: enum Enum {
+CHECK-DAG: RED,
+CHECK-DAG: GREEN,
+CHECK-DAG: BLUE
+CHECK-DAG:}
+
+CHECK-DAG: name = "MemberTest::Base", size = 4, decl = ClassLayoutTest.cpp:56
+CHECK-SAME: class MemberTest::Base {
+CHECK-DAG: int a;
+CHECK-DAG: void {{.*}}Base();
+CHECK-DAG: {{.*}}~Base();
+CHECK-DAG: int {{.*}}Get();
+CHECK-DAG:}
+
+CHECK-DAG: name = "Union", size = 4, decl = ClassLayoutTest.cpp:8
+CHECK-SAME: union Union {
+CHECK-DAG: short Row;
+CHECK-DAG: unsigned short Col;
+CHECK-DAG: int Line : 16;
+CHECK-DAG: long Table;
+CHECK-DAG:}
+
+CHECK-DAG: name = "Struct", size = 64, decl = ClassLayoutTest.cpp:21
+CHECK-SAME: struct Struct {
+CHECK-DAG: bool A;
+CHECK-DAG: unsigned char UCharVar;
+CHECK-DAG: unsigned int UIntVar;
+CHECK-DAG: long long LongLongVar;
+CHECK-DAG: Enum EnumVar;
+CHECK-DAG: int array[10];
+CHECK-DAG:}
+
+CHECK-DAG: name = "_List", size = 12, decl = ClassLayoutTest.cpp:44
+CHECK-SAME: struct _List {
+CHECK-DAG: _List *current;
+CHECK-DAG: _List *previous;
+CHECK-DAG: _List *next;
+CHECK-DAG:}
+
+CHECK-DAG: name = "Complex", size = 368, decl = ClassLayoutTest.cpp:32
+CHECK-SAME: struct Complex {
+CHECK-DAG: _List *array[90];
+CHECK-DAG: int x;
+CHECK-DAG: int a;
+CHECK-DAG: float b;
+CHECK-DAG:}
+
+CHECK-DAG: name = "MemberTest::Friend", size = 1, decl = ClassLayoutTest.cpp:66
+CHECK-SAME: class MemberTest::Friend {
+CHECK-DAG: int f();
+CHECK-DAG: }
+
+CHECK-DAG: name = "MemberTest::Class", size = 88, decl = ClassLayoutTest.cpp:70
+CHECK-SAME: class MemberTest::Class : public MemberTest::Base {
+CHECK-DAG: static int m_static;
+CHECK-DAG: int m_public;
+CHECK-DAG: Struct m_struct;
+CHECK-DAG: Union m_union;
+CHECK-DAG: int m_private;
+CHECK-DAG: int m_protected;
+CHECK-DAG: void Class();
+CHECK-DAG: void Class(int);
+CHECK-DAG: ~MemberTest::Class();
+CHECK-DAG: static int {{.*}}StaticMemberFunc(int, ...);
+CHECK-DAG: int Get();
+CHECK-DAG: int f(MemberTest::Friend);
+CHECK-DAG: bool operator==(const MemberTest::Class &)
+CHECK-DAG:}
+
+CHECK-DAG: name = "UnnamedStruct", size = 4, decl = ClassLayoutTest.cpp:51
+CHECK-SAME: struct UnnamedStruct {
+CHECK-DAG: int a;
+CHECK-DAG:}
+
+CHECK-DAG: {{^[0-9A-F]+}}: CompileUnit{{[{]0x[0-9a-f]+[}]}}, language = "c++", file = '{{.*}}\ClassLayoutTest.cpp'
Index: lit/SymbolFile/PDB/Inputs/PointerTypeTest.cpp
===================================================================
--- /dev/null
+++ lit/SymbolFile/PDB/Inputs/PointerTypeTest.cpp
@@ -0,0 +1,25 @@
+
+int main() {
+
+ // Test pointer to array.
+ int array[2][4];
+ int (*array_pointer)[2][4] = &array;
+
+ struct ST {
+ int a;
+ int f(int x) { return 1; }
+ };
+
+ ST s = { 10 };
+
+ // Test pointer to a local.
+ int *p_int = &s.a;
+
+ // Test pointer to data member.
+ int ST:: *p_member_field = &ST::a;
+
+ // Test pointer to member function.
+ int (ST::*p_member_method)(int) = &ST::f;
+
+ return 0;
+}
Index: lit/SymbolFile/PDB/Inputs/ClassLayoutTest.cpp
===================================================================
--- /dev/null
+++ lit/SymbolFile/PDB/Inputs/ClassLayoutTest.cpp
@@ -0,0 +1,103 @@
+// To avoid linking MSVC specific libs, we don't test virtual/override methods that needs vftable support in this file.
+
+// Enum.
+enum Enum { RED, GREEN, BLUE };
+Enum EnumVar;
+
+// Union.
+union Union {
+ short Row;
+ unsigned short Col;
+ int Line : 16; // Test named bitfield.
+ short : 8; // Unnamed bitfield symbol won't be generated in PDB.
+ long Table;
+};
+Union UnionVar;
+
+// Struct.
+struct Struct;
+typedef Struct StructTypedef;
+
+struct Struct {
+ bool A;
+ unsigned char UCharVar;
+ unsigned int UIntVar;
+ long long LongLongVar;
+ Enum EnumVar; // Test struct has UDT member.
+ int array[10];
+};
+struct Struct StructVar;
+
+struct _List; // Forward declaration.
+struct Complex {
+ struct _List* array[90];
+ struct { // Test unnamed struct. MSVC treats it as `int x`
+ int x;
+ };
+ union { // Test unnamed union. MSVC treats it as `int a; float b;`
+ int a;
+ float b;
+ };
+};
+struct Complex c;
+
+struct _List { // Test doubly linked list.
+ struct _List* current;
+ struct _List* previous;
+ struct _List* next;
+};
+struct _List ListVar;
+
+typedef struct { int a; } UnnamedStruct; // Test unnamed typedef-ed struct.
+UnnamedStruct UnnanmedVar;
+
+// Class.
+namespace MemberTest {
+class Base {
+ public:
+ Base() {}
+ ~Base() {}
+
+ public:
+ int Get() { return 0; }
+ protected:
+ int a;
+};
+ class Friend {
+ public:
+ int f() { return 3; }
+ };
+ class Class : public Base { // Test base class.
+ friend Friend;
+ static int m_static; // Test static member variable.
+ public:
+ Class() : m_public(), m_private(), m_protected() {}
+ explicit Class(int a) { m_public = a; } // Test first reference of m_public.
+ ~Class() {}
+
+ static int StaticMemberFunc(int a, ...) { return 1; } // Test static member function.
+ int Get() { return 1; }
+ int f(Friend c) { return c.f(); }
+ inline bool operator == (const Class &rhs) const // Test operator.
+ {
+ return ( m_public == rhs.m_public);
+ }
+
+ public:
+ int m_public;
+ struct Struct m_struct;
+ private:
+ Union m_union;
+ int m_private;
+ protected:
+ friend class Friend;
+ int m_protected;
+ };
+}
+
+int main() {
+ MemberTest::Base B1;
+ B1.Get();
+ MemberTest::Class::StaticMemberFunc(1,10,2);
+ return 0;
+}
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits