This revision was automatically updated to reflect the committed changes.
Closed by commit rL345848: [NativePDB] Get LLDB types from PDB function types. 
(authored by zturner, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D53951?vs=172023&id=172151#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D53951

Files:
  lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-builtins.lldbinit
  
lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-calling-conv.lldbinit
  lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit
  lldb/trunk/lit/SymbolFile/NativePDB/function-types-builtins.cpp
  lldb/trunk/lit/SymbolFile/NativePDB/function-types-calling-conv.cpp
  lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp
  lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
  lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
  lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
  llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h

Index: lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -49,6 +49,8 @@
 #include "llvm/Support/ErrorOr.h"
 #include "llvm/Support/MemoryBuffer.h"
 
+#include "Plugins/Language/CPlusPlus/CPlusPlusNameParser.h"
+
 #include "PdbSymUid.h"
 #include "PdbUtil.h"
 #include "UdtRecordCompleter.h"
@@ -394,6 +396,12 @@
   return GetPdbSymType(tpi, LookThroughModifierRecord(cvt));
 }
 
+static bool IsCVarArgsFunction(llvm::ArrayRef<TypeIndex> args) {
+  if (args.empty())
+    return false;
+  return args.back() == TypeIndex::None();
+}
+
 static clang::TagTypeKind TranslateUdtKind(const TagRecord &cr) {
   switch (cr.Kind) {
   case TypeRecordKind::Class:
@@ -412,6 +420,32 @@
   }
 }
 
+static llvm::Optional<clang::CallingConv>
+TranslateCallingConvention(llvm::codeview::CallingConvention conv) {
+  using CC = llvm::codeview::CallingConvention;
+  switch (conv) {
+
+  case CC::NearC:
+  case CC::FarC:
+    return clang::CallingConv::CC_C;
+  case CC::NearPascal:
+  case CC::FarPascal:
+    return clang::CallingConv::CC_X86Pascal;
+  case CC::NearFast:
+  case CC::FarFast:
+    return clang::CallingConv::CC_X86FastCall;
+  case CC::NearStdCall:
+  case CC::FarStdCall:
+    return clang::CallingConv::CC_X86StdCall;
+  case CC::ThisCall:
+    return clang::CallingConv::CC_X86ThisCall;
+  case CC::NearVector:
+    return clang::CallingConv::CC_X86VectorCall;
+  default:
+    return llvm::None;
+  }
+}
+
 void SymbolFileNativePDB::Initialize() {
   PluginManager::RegisterPlugin(GetPluginNameStatic(),
                                 GetPluginDescriptionStatic(), CreateInstance,
@@ -540,7 +574,6 @@
   PdbSymUid sig_uid =
       PdbSymUid::makeTypeSymId(PDB_SymType::FunctionSig, TypeIndex{0}, false);
   Mangled mangled(getSymbolName(sym_record));
-
   FunctionSP func_sp = std::make_shared<Function>(
       sc.comp_unit, func_uid.toOpaqueId(), sig_uid.toOpaqueId(), mangled,
       func_type, func_range);
@@ -598,6 +631,8 @@
 lldb::TypeSP SymbolFileNativePDB::CreatePointerType(
     PdbSymUid type_uid, const llvm::codeview::PointerRecord &pr) {
   TypeSP pointee = GetOrCreateType(pr.ReferentType);
+  if (!pointee)
+    return nullptr;
   CompilerType pointee_ct = pointee->GetForwardCompilerType();
   lldbassert(pointee_ct);
   Declaration decl;
@@ -639,6 +674,17 @@
 }
 
 lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti) {
+  if (ti == TypeIndex::NullptrT()) {
+    PdbSymUid uid =
+        PdbSymUid::makeTypeSymId(PDB_SymType::BuiltinType, ti, false);
+    CompilerType ct = m_clang->GetBasicType(eBasicTypeNullPtr);
+    Declaration decl;
+    return std::make_shared<Type>(uid.toOpaqueId(), this,
+                                  ConstString("std::nullptr_t"), 0, nullptr,
+                                  LLDB_INVALID_UID, Type::eEncodingIsUID, decl,
+                                  ct, Type::eResolveStateFull);
+  }
+
   if (ti.getSimpleMode() != SimpleTypeMode::Direct) {
     PdbSymUid uid =
         PdbSymUid::makeTypeSymId(PDB_SymType::PointerType, ti, false);
@@ -670,7 +716,8 @@
     return nullptr;
 
   lldb::BasicType bt = GetCompilerTypeForSimpleKind(ti.getSimpleKind());
-  lldbassert(bt != lldb::eBasicTypeInvalid);
+  if (bt == lldb::eBasicTypeInvalid)
+    return nullptr;
   CompilerType ct = m_clang->GetBasicType(bt);
   size_t size = GetTypeSizeForSimpleKind(ti.getSimpleKind());
 
@@ -687,10 +734,6 @@
     PdbSymUid type_uid, llvm::StringRef name, size_t size,
     clang::TagTypeKind ttk, clang::MSInheritanceAttr::Spelling inheritance) {
 
-  // Some UDT with trival ctor has zero length. Just ignore.
-  if (size == 0)
-    return nullptr;
-
   // Ignore unnamed-tag UDTs.
   name = DropNameScope(name);
   if (name.empty())
@@ -792,6 +835,49 @@
   return array_sp;
 }
 
+TypeSP SymbolFileNativePDB::CreateProcedureType(PdbSymUid type_uid,
+                                                const ProcedureRecord &pr) {
+  TpiStream &stream = m_index->tpi();
+  CVType args_cvt = stream.getType(pr.ArgumentList);
+  ArgListRecord args;
+  llvm::cantFail(
+      TypeDeserializer::deserializeAs<ArgListRecord>(args_cvt, args));
+
+  llvm::ArrayRef<TypeIndex> arg_indices = llvm::makeArrayRef(args.ArgIndices);
+  bool is_variadic = IsCVarArgsFunction(arg_indices);
+  if (is_variadic)
+    arg_indices = arg_indices.drop_back();
+
+  std::vector<CompilerType> arg_list;
+  arg_list.reserve(arg_list.size());
+
+  for (TypeIndex arg_index : arg_indices) {
+    TypeSP arg_sp = GetOrCreateType(arg_index);
+    if (!arg_sp)
+      return nullptr;
+    arg_list.push_back(arg_sp->GetFullCompilerType());
+  }
+
+  TypeSP return_type_sp = GetOrCreateType(pr.ReturnType);
+  if (!return_type_sp)
+    return nullptr;
+
+  llvm::Optional<clang::CallingConv> cc =
+      TranslateCallingConvention(pr.CallConv);
+  if (!cc)
+    return nullptr;
+
+  CompilerType return_ct = return_type_sp->GetFullCompilerType();
+  CompilerType func_sig_ast_type = m_clang->CreateFunctionType(
+      return_ct, arg_list.data(), arg_list.size(), is_variadic, 0, *cc);
+
+  Declaration decl;
+  return std::make_shared<lldb_private::Type>(
+      type_uid.toOpaqueId(), this, ConstString(), 0, nullptr, LLDB_INVALID_UID,
+      lldb_private::Type::eEncodingIsUID, decl, func_sig_ast_type,
+      lldb_private::Type::eResolveStateFull);
+}
+
 TypeSP SymbolFileNativePDB::CreateType(PdbSymUid type_uid) {
   const PdbTypeSymId &tsid = type_uid.asTypeSym();
   TypeIndex index(tsid.index);
@@ -840,6 +926,12 @@
     return CreateArrayType(type_uid, ar);
   }
 
+  if (cvt.kind() == LF_PROCEDURE) {
+    ProcedureRecord pr;
+    llvm::cantFail(TypeDeserializer::deserializeAs<ProcedureRecord>(cvt, pr));
+    return CreateProcedureType(type_uid, pr);
+  }
+
   return nullptr;
 }
 
@@ -858,7 +950,7 @@
       auto expected_full_ti = m_index->tpi().findFullDeclForForwardRef(ti);
       if (!expected_full_ti)
         llvm::consumeError(expected_full_ti.takeError());
-      else {
+      else if (*expected_full_ti != ti) {
         full_decl_uid = PdbSymUid::makeTypeSymId(
             type_uid.tag(), *expected_full_ti, type_id.is_ipi);
 
@@ -880,6 +972,8 @@
 
   PdbSymUid best_uid = full_decl_uid ? *full_decl_uid : type_uid;
   TypeSP result = CreateType(best_uid);
+  if (!result)
+    return nullptr;
   m_types[best_uid.toOpaqueId()] = result;
   // If we had both a forward decl and a full decl, make both point to the new
   // type.
Index: lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -172,6 +172,8 @@
                              const llvm::codeview::UnionRecord &ur);
   lldb::TypeSP CreateArrayType(PdbSymUid type_uid,
                                const llvm::codeview::ArrayRecord &ar);
+  lldb::TypeSP CreateProcedureType(PdbSymUid type_uid,
+                                   const llvm::codeview::ProcedureRecord &pr);
   lldb::TypeSP
   CreateClassStructUnion(PdbSymUid type_uid, llvm::StringRef name, size_t size,
                          clang::TagTypeKind ttk,
Index: lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
@@ -92,6 +92,8 @@
     return PDB_SymType::PointerType;
   case LF_ENUM:
     return PDB_SymType::Enum;
+  case LF_PROCEDURE:
+    return PDB_SymType::FunctionSig;
   default:
     lldbassert(false && "Invalid type record kind!");
   }
@@ -361,4 +363,4 @@
   assert(offset + 2 <= name.size());
 
   return name.substr(offset + 2);
-}
\ No newline at end of file
+}
Index: lldb/trunk/lit/SymbolFile/NativePDB/function-types-builtins.cpp
===================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/function-types-builtins.cpp
+++ lldb/trunk/lit/SymbolFile/NativePDB/function-types-builtins.cpp
@@ -0,0 +1,215 @@
+// clang-format off
+// REQUIRES: lld
+
+// RUN: clang-cl /Z7 /GS- /GR- /c -Xclang -fkeep-static-consts /Fo%t.obj -- %s
+// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
+// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \
+// RUN:     %p/Inputs/function-types-builtins.lldbinit | FileCheck %s
+
+// Test that we can display function signatures with simple builtin
+// and pointer types.  We do this by using `target variable` in lldb
+// with global variables of type ptr-to-function or reference-to-function.
+// This technique in general allows us to exercise most of LLDB's type
+// system without a running process.
+
+template<typename T>
+struct MakeResult {
+  static T result() {
+    return T{};
+  }
+};
+
+template<typename T>
+struct MakeResult<T&> {
+  static T& result() {
+    static T t;
+    return t;
+  }
+};
+
+template<typename T>
+struct MakeResult<T&&> {
+  static T&& result() {
+    static T t;
+    return static_cast<T&&>(t);
+  }
+};
+
+
+void nullary() {}
+
+template<typename Arg>
+void unary(Arg) { }
+
+template<typename Ret, int N>
+Ret unaryret() { return MakeResult<Ret>::result(); }
+
+template<typename A1, typename A2>
+void binary(A1, A2) { }
+
+int varargs(int, int, ...) { return 0; }
+
+// Make sure to test every builtin type at least once for completeness.  We
+// test these in the globals-fundamentals.cpp when they are the types of
+// variables but it's possible to imagine a situation where things behave
+// differently as function arguments or return values than they do with
+// global variables.
+
+// some interesting cases with argument types.
+auto aa = &unary<bool>;
+// CHECK: (void (*)(bool)) aa = {{.*}}
+auto ab = &unary<char>;
+// CHECK: (void (*)(char)) ab = {{.*}}
+auto ac = &unary<signed char>;
+// CHECK: (void (*)(signed char)) ac = {{.*}}
+auto ad = &unary<unsigned char>;
+// CHECK: (void (*)(unsigned char)) ad = {{.*}}
+auto ae = &unary<char16_t>;
+// CHECK: (void (*)(char16_t)) ae = {{.*}}
+auto af = &unary<char32_t>;
+// CHECK: (void (*)(char32_t)) af = {{.*}}
+auto ag = &unary<wchar_t>;
+// CHECK: (void (*)(wchar_t)) ag = {{.*}}
+auto ah = &unary<short>;
+// CHECK: (void (*)(short)) ah = {{.*}}
+auto ai = &unary<unsigned short>;
+// CHECK: (void (*)(unsigned short)) ai = {{.*}}
+auto aj = &unary<int>;
+// CHECK: (void (*)(int)) aj = {{.*}}
+auto ak = &unary<unsigned int>;
+// CHECK: (void (*)(unsigned int)) ak = {{.*}}
+auto al = &unary<long>;
+// CHECK: (void (*)(long)) al = {{.*}}
+auto am = &unary<unsigned long>;
+// CHECK: (void (*)(unsigned long)) am = {{.*}}
+auto an = &unary<long long>;
+// CHECK: (void (*)(long long)) an = {{.*}}
+auto ao = &unary<unsigned long long>;
+// CHECK: (void (*)(unsigned long long)) ao = {{.*}}
+auto aq = &unary<float>;
+// CHECK: (void (*)(float)) aq = {{.*}}
+auto ar = &unary<double>;
+// CHECK: (void (*)(double)) ar = {{.*}}
+
+auto as = &unary<int*>;
+// CHECK: (void (*)(int *)) as = {{.*}}
+auto at = &unary<int**>;
+// CHECK: (void (*)(int **)) at = {{.*}}
+auto au = &unary<int&>;
+// CHECK: (void (*)(int &)) au = {{.*}}
+auto av = &unary<int&&>;
+// CHECK: (void (*)(int &&)) av = {{.*}}
+auto aw = &unary<const int*>;
+// CHECK: (void (*)(const int *)) aw = {{.*}}
+auto ax = &unary<volatile int*>;
+// CHECK: (void (*)(volatile int *)) ax = {{.*}}
+auto ay = &unary<const volatile int*>;
+// CHECK: (void (*)(const volatile int *)) ay = {{.*}}
+auto az = &unary<void*&>;
+// CHECK: (void (*)(void *&)) az = {{.*}}
+auto aaa = &unary<int(&)[5]>;
+// CHECK: (void (*)(int (&)[5])) aaa = {{.*}}
+auto aab = &unary<int(*)[5]>;
+// CHECK: (void (*)(int (*)[5])) aab = {{.*}}
+auto aac = &unary<int(&&)[5]>;
+// CHECK: (void (*)(int (&&)[5])) aac = {{.*}}
+auto aad = &unary<int(*const)[5]>;
+// CHECK: (void (*)(int (*)[5])) aad = {{.*}}
+
+
+// same test cases with return values, note we can't overload on return type
+// so we need to use a different instantiation each time.
+auto ra = &unaryret<bool, 0>;
+// CHECK: (bool (*)()) ra = {{.*}}
+auto rb = &unaryret<char, 1>;
+// CHECK: (char (*)()) rb = {{.*}}
+auto rc = &unaryret<signed char, 2>;
+// CHECK: (signed char (*)()) rc = {{.*}}
+auto rd = &unaryret<unsigned char, 3>;
+// CHECK: (unsigned char (*)()) rd = {{.*}}
+auto re = &unaryret<char16_t, 4>;
+// CHECK: (char16_t (*)()) re = {{.*}}
+auto rf = &unaryret<char32_t, 5>;
+// CHECK: (char32_t (*)()) rf = {{.*}}
+auto rg = &unaryret<wchar_t, 6>;
+// CHECK: (wchar_t (*)()) rg = {{.*}}
+auto rh = &unaryret<short, 7>;
+// CHECK: (short (*)()) rh = {{.*}}
+auto ri = &unaryret<unsigned short, 8>;
+// CHECK: (unsigned short (*)()) ri = {{.*}}
+auto rj = &unaryret<int, 9>;
+// CHECK: (int (*)()) rj = {{.*}}
+auto rk = &unaryret<unsigned int, 10>;
+// CHECK: (unsigned int (*)()) rk = {{.*}}
+auto rl = &unaryret<long, 11>;
+// CHECK: (long (*)()) rl = {{.*}}
+auto rm = &unaryret<unsigned long, 12>;
+// CHECK: (unsigned long (*)()) rm = {{.*}}
+auto rn = &unaryret<long long, 13>;
+// CHECK: (long long (*)()) rn = {{.*}}
+auto ro = &unaryret<unsigned long long, 14>;
+// CHECK: (unsigned long long (*)()) ro = {{.*}}
+auto rq = &unaryret<float, 15>;
+// CHECK: (float (*)()) rq = {{.*}}
+auto rr = &unaryret<double, 16>;
+// CHECK: (double (*)()) rr = {{.*}}
+
+auto rs = &unaryret<int*, 17>;
+// CHECK: (int *(*)()) rs = {{.*}}
+auto rt = &unaryret<int**, 18>;
+// CHECK: (int **(*)()) rt = {{.*}}
+auto ru = &unaryret<int&, 19>;
+// CHECK: (int &(*)()) ru = {{.*}}
+auto rv = &unaryret<int&&, 20>;
+// CHECK: (int &&(*)()) rv = {{.*}}
+auto rw = &unaryret<const int*, 21>;
+// CHECK: (const int *(*)()) rw = {{.*}}
+auto rx = &unaryret<volatile int*, 22>;
+// CHECK: (volatile int *(*)()) rx = {{.*}}
+auto ry = &unaryret<const volatile int*, 23>;
+// CHECK: (const volatile int *(*)()) ry = {{.*}}
+auto rz = &unaryret<void*&, 24>;
+// CHECK: (void *&(*)()) rz = {{.*}}
+
+// FIXME: This output doesn't really look correct.  It should probably be
+// formatting this as `int(&)[5] (*)()`.
+auto raa = &unaryret<int(&)[5], 25>;
+// CHECK: (int (&(*)())[5]) raa = {{.*}}
+auto rab = &unaryret<int(*)[5], 26>;
+// CHECK: (int (*(*)())[5]) rab = {{.*}}
+auto rac = &unaryret<int(&&)[5], 27>;
+// CHECK: (int (&&(*)())[5]) rac = {{.*}}
+auto rad = &unaryret<int(*const)[5], 28>;
+// CHECK: (int (*const (*)())[5]) rad = {{.*}}
+
+
+
+// Function references, we only need a couple of these since most of the
+// interesting cases are already tested.
+auto &ref = unary<bool>;
+// CHECK: (void (&)(bool)) ref = {{.*}} (&::ref = <Unable to determine byte size.>)
+auto &ref2 = unary<volatile int*>;
+// CHECK: (void (&)(volatile int *)) ref2 = {{.*}} (&::ref2 = <Unable to determine byte size.>)
+auto &ref3 = varargs;
+// CHECK: (int (&)(int, int, ...)) ref3 = {{.*}} (&::ref3 = <Unable to determine byte size.>)
+
+// Multiple arguments, as before, just something to make sure it works.
+auto binp = &binary<int*, const int*>;
+// CHECK: (void (*)(int *, const int *)) binp = {{.*}}
+auto &binr = binary<int*, const int*>;
+// CHECK: (void (&)(int *, const int *)) binr = {{.*}} (&::binr = <Unable to determine byte size.>)
+
+// And finally, a function with no arguments.
+auto null = &nullary;
+// CHECK: (void (*)()) null = {{.*}}
+
+// FIXME: These currently don't work because clang-cl emits incorrect debug info
+// for std::nullptr_t.  We should fix these in clang-cl.
+auto rae = &unaryret<decltype(nullptr), 29>;
+// CHECK: (nullptr_t (*)()) rae = {{.*}}
+auto aae = &unary<decltype(nullptr)>;
+// CHECK: (void (*)(nullptr_t)) aae = {{.*}}
+
+int main(int argc, char **argv) {
+  return 0;
+}
Index: lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp
===================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp
+++ lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp
@@ -0,0 +1,118 @@
+// clang-format off
+// REQUIRES: lld
+
+// Test that we can display function signatures with class types.
+// RUN: clang-cl /Z7 /GS- /GR- /c -Xclang -fkeep-static-consts /Fo%t.obj -- %s
+// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
+// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \
+// RUN:     %p/Inputs/function-types-classes.lldbinit | FileCheck %s
+
+// This is just some unimportant helpers needed so that we can get reference and
+// rvalue-reference types into return values.
+template<typename T>
+struct MakeResult {
+  static T result() {
+    return T{};
+  }
+};
+
+template<typename T>
+struct MakeResult<T&> {
+  static T& result() {
+    static T t;
+    return t;
+  }
+};
+
+template<typename T>
+struct MakeResult<T&&> {
+  static T&& result() {
+    static T t;
+    return static_cast<T&&>(t);
+  }
+};
+
+
+template<typename R>
+R nullary() { return MakeResult<R>::result(); }
+
+template<typename R, typename A, typename B>
+R three(A a, B b) { return MakeResult<R>::result(); }
+
+template<typename R, typename A, typename B, typename C>
+R four(A a, B b, C c) { return MakeResult<R>::result(); }
+
+struct S {};
+class C {};
+union U {};
+enum E {};
+
+namespace A {
+  namespace B {
+    // NS::NS
+    struct S { };
+  }
+
+  struct C {
+    // NS::Struct
+    struct S {};
+  };
+}
+
+struct B {
+  struct A {
+    // Struct::Struct
+    struct S {};
+  };
+};
+
+template<typename T>
+struct TC {};
+
+// const and volatile modifiers
+auto a = &four<S, C*, U&, E&&>;
+// CHECK: (S (*)(C *, U &, E &&)) a = {{.*}}
+auto b = &four<E, const S*, const C&, const U&&>;
+// CHECK: (E (*)(const S *, const C &, const U &&)) b = {{.*}}
+auto c = &four<U, volatile E*, volatile S&, volatile C&&>;
+// CHECK: (U (*)(volatile E *, volatile S &, volatile C &&)) c = {{.*}}
+auto d = &four<C, const volatile U*, const volatile E&, const volatile S&&>;
+// CHECK: (C (*)(const volatile U *, const volatile E &, const volatile S &&)) d = {{.*}}
+
+// classes nested in namespaces and inner classes
+
+// FIXME: LLDB with native pdb plugin doesn't currently resolve nested names
+// correctly, because it requires creating clang::NamespaceDecl or
+// clang::RecordDecl for the outer namespace or classes.  PDB doesn't contain
+// sufficient information to distinguish namespace scopes from nested class
+// scopes, so the best we can hope for is a heuristic reconstruction of the
+// clang AST based on demangling the type's unique name.  However, this is
+// as-yet unimplemented in the native PDB plugin, so for now all of these will
+// all just look like `S` when LLDB prints them.
+auto e = &three<A::B::S*, B::A::S*, A::C::S&>;
+// CHECK: (S *(*)(S *, S &)) e = {{.*}}
+auto f = &three<A::C::S&, A::B::S*, B::A::S*>;
+// CHECK: (S &(*)(S *, S *)) f = {{.*}}
+auto g = &three<B::A::S*, A::C::S&, A::B::S*>;
+// CHECK: (S *(*)(S &, S *)) g = {{.*}}
+
+// parameter types that are themselves template instantiations.
+auto h = &four<TC<void>, TC<int>, TC<TC<int>>, TC<A::B::S>>;
+// Note the awkward space in TC<TC<int> >.  This is because this is how template
+// instantiations are emitted by the compiler, as the fully instantiated name.
+// Only via reconstruction of the AST through the mangled type name (see above
+// comment) can we hope to do better than this).
+// CHECK: (TC<void> (*)(TC<int>, TC<TC<int> >, S>)) h = {{.*}}
+
+auto i = &nullary<A::B::S>;
+// CHECK: (S (*)()) i = {{.*}}
+
+
+// Make sure we can handle types that don't have complete debug info.
+struct Incomplete;
+auto incomplete = &three<Incomplete*, Incomplete**, const Incomplete*>;
+// CHECK: (Incomplete *(*)(Incomplete **, const Incomplete *)) incomplete = {{.*}}
+
+int main(int argc, char **argv) {
+  return 0;
+}
Index: lldb/trunk/lit/SymbolFile/NativePDB/function-types-calling-conv.cpp
===================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/function-types-calling-conv.cpp
+++ lldb/trunk/lit/SymbolFile/NativePDB/function-types-calling-conv.cpp
@@ -0,0 +1,33 @@
+// clang-format off
+// REQUIRES: lld
+
+// RUN: clang-cl -m32 /Z7 /GS- /GR- /c -Xclang -fkeep-static-consts /Fo%t.obj -- %s
+// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
+// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \
+// RUN:     %p/Inputs/function-types-calling-conv.lldbinit | FileCheck %s
+
+
+void __stdcall StdcallFn() {}
+void __fastcall FastcallFn() {}
+void __thiscall ThiscallFn() {}
+void __cdecl CdeclFn() {}
+void __vectorcall VectorcallFn() {}
+
+auto sfn = &StdcallFn;
+// CHECK: (void (*)() __attribute__((stdcall))) sfn = {{.*}}
+
+auto ffn = &FastcallFn;
+// CHECK: (void (*)() __attribute__((fastcall))) ffn = {{.*}}
+
+auto tfn = &ThiscallFn;
+// CHECK: (void (*)() __attribute__((thiscall))) tfn = {{.*}}
+
+auto cfn = &CdeclFn;
+// CHECK: (void (*)()) cfn = {{.*}}
+
+auto vfn = &VectorcallFn;
+// CHECK: (void (*)() __attribute__((vectorcall))) vfn = {{.*}}
+
+int main(int argc, char **argv) {
+  return 0;
+}
\ No newline at end of file
Index: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-calling-conv.lldbinit
===================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-calling-conv.lldbinit
+++ lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-calling-conv.lldbinit
@@ -0,0 +1,7 @@
+target variable sfn
+target variable ffn
+target variable tfn
+target variable cfn
+target variable vfn
+
+quit
Index: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-builtins.lldbinit
===================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-builtins.lldbinit
+++ lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-builtins.lldbinit
@@ -0,0 +1,70 @@
+command alias dv target variable
+
+dv aa
+dv ab
+dv ac
+dv ad
+dv ae
+dv af
+dv ag
+dv ah
+dv ai
+dv aj
+dv ak
+dv al
+dv am
+dv an
+dv ao
+dv aq
+dv ar
+dv as
+dv at
+dv au
+dv av
+dv aw
+dv ax
+dv ay
+dv az
+dv aaa
+dv aab
+dv aac
+dv aad
+dv ra
+dv rb
+dv rc
+dv rd
+dv re
+dv rf
+dv rg
+dv rh
+dv ri
+dv rj
+dv rk
+dv rl
+dv rm
+dv rn
+dv ro
+dv rq
+dv rr
+dv rs
+dv rt
+dv ru
+dv rv
+dv rw
+dv rx
+dv ry
+dv rz
+dv raa
+dv rab
+dv rac
+dv rad
+dv ref
+dv ref2
+dv ref3
+dv binp
+dv binr
+dv null
+dv rae
+dv aae
+
+quit
Index: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit
===================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit
+++ lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit
@@ -0,0 +1,12 @@
+target variable a
+target variable b
+target variable c
+target variable d
+target variable e
+target variable f
+target variable g
+target variable h
+target variable i
+target variable incomplete
+
+quit
Index: llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h
===================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h
@@ -47,7 +47,7 @@
     return Error::success();
   }
   template <typename T> static Expected<T> deserializeAs(CVSymbol Symbol) {
-    T Record(Symbol.kind());
+    T Record(static_cast<SymbolRecordKind>(Symbol.kind()));
     if (auto EC = deserializeAs<T>(Symbol, Record))
       return std::move(EC);
     return Record;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to