[Lldb-commits] [lldb] 895529c - [lldb][PDB] Constexpr static member values as AST literals

Aleksandr Urakov via lldb-commits lldb-commits at lists.llvm.org
Thu Jun 25 01:27:47 PDT 2020


Author: Aleksandr Urakov
Date: 2020-06-25T11:27:16+03:00
New Revision: 895529cfd8756e2b4dc609f5af92e0d8ae280ed8

URL: https://github.com/llvm/llvm-project/commit/895529cfd8756e2b4dc609f5af92e0d8ae280ed8
DIFF: https://github.com/llvm/llvm-project/commit/895529cfd8756e2b4dc609f5af92e0d8ae280ed8.diff

LOG: [lldb][PDB] Constexpr static member values as AST literals

Summary:
When evaluating an expression referencing a constexpr static member variable, an
error is issued because the PDB does not specify a symbol with an address that
can be relocated against.

Rather than attempt to resolve the variable's value within the IR execution, the
values of all constants can be looked up and incorporated into the AST of the
record type as a literal, mirroring the original compiler AST.

This change applies to DIA and native PDB loaders.

Patch By: jackoalan

Reviewers: aleksandr.urakov, jasonmolenda, zturner, jdoerfert, teemperor

Reviewed By: aleksandr.urakov

Subscribers: sstefan1, lldb-commits, llvm-commits, #lldb

Tags: #lldb, #llvm

Differential Revision: https://reviews.llvm.org/D82160

Added: 
    

Modified: 
    lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
    lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
    lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
    lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
    lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
    lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
    lldb/test/Shell/SymbolFile/PDB/Inputs/AstRestoreTest.cpp
    lldb/test/Shell/SymbolFile/PDB/ast-restore.test
    llvm/include/llvm/DebugInfo/PDB/PDBTypes.h

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
index b88f87527d8c..0acc77d7c67f 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -681,7 +681,7 @@ bool PdbAstBuilder::CompleteTagDecl(clang::TagDecl &tag) {
   // Visit all members of this class, then perform any finalization necessary
   // to complete the class.
   CompilerType ct = ToCompilerType(tag_qt);
-  UdtRecordCompleter completer(best_ti, ct, tag, *this, m_index.tpi());
+  UdtRecordCompleter completer(best_ti, ct, tag, *this, m_index);
   auto error =
       llvm::codeview::visitMemberRecordStream(field_list_cvt.data(), completer);
   completer.complete();

diff  --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
index 308ba9e3dec0..c8fb46c75034 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -6,14 +6,17 @@
 #include "PdbUtil.h"
 
 #include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "lldb/Symbol/Type.h"
 #include "lldb/Utility/LLDBAssert.h"
 #include "lldb/lldb-enumerations.h"
 #include "lldb/lldb-forward.h"
 
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
 #include "llvm/DebugInfo/PDB/PDBTypes.h"
 
@@ -29,10 +32,10 @@ UdtRecordCompleter::UdtRecordCompleter(PdbTypeSymId id,
                                        CompilerType &derived_ct,
                                        clang::TagDecl &tag_decl,
                                        PdbAstBuilder &ast_builder,
-                                       TpiStream &tpi)
+                                       PdbIndex &index)
     : m_id(id), m_derived_ct(derived_ct), m_tag_decl(tag_decl),
-      m_ast_builder(ast_builder), m_tpi(tpi) {
-  CVType cvt = m_tpi.getType(m_id.index);
+      m_ast_builder(ast_builder), m_index(index) {
+  CVType cvt = m_index.tpi().getType(m_id.index);
   switch (cvt.kind()) {
   case LF_ENUM:
     llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er));
@@ -55,7 +58,7 @@ clang::QualType UdtRecordCompleter::AddBaseClassForTypeIndex(
   PdbTypeSymId type_id(ti);
   clang::QualType qt = m_ast_builder.GetOrCreateType(type_id);
 
-  CVType udt_cvt = m_tpi.getType(ti);
+  CVType udt_cvt = m_index.tpi().getType(ti);
 
   std::unique_ptr<clang::CXXBaseSpecifier> base_spec =
       m_ast_builder.clang().CreateBaseClassSpecifier(
@@ -128,9 +131,70 @@ Error UdtRecordCompleter::visitKnownMember(
 
   lldb::AccessType access =
       TranslateMemberAccess(static_data_member.getAccess());
-  TypeSystemClang::AddVariableToRecordType(
+  auto decl = TypeSystemClang::AddVariableToRecordType(
       m_derived_ct, static_data_member.Name, member_ct, access);
 
+  // Static constant members may be a const[expr] declaration.
+  // Query the symbol's value as the variable initializer if valid.
+  if (member_ct.IsConst()) {
+    std::string qual_name = decl->getQualifiedNameAsString();
+
+    auto results =
+        m_index.globals().findRecordsByName(qual_name, m_index.symrecords());
+
+    for (const auto &result : results) {
+      if (result.second.kind() == SymbolKind::S_CONSTANT) {
+        ConstantSym constant(SymbolRecordKind::ConstantSym);
+        cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(result.second,
+                                                                constant));
+
+        clang::QualType qual_type = decl->getType();
+        unsigned type_width = decl->getASTContext().getIntWidth(qual_type);
+        unsigned constant_width = constant.Value.getBitWidth();
+
+        if (qual_type->isIntegralOrEnumerationType()) {
+          if (type_width >= constant_width) {
+            TypeSystemClang::SetIntegerInitializerForVariable(
+                decl, constant.Value.extOrTrunc(type_width));
+          } else {
+            LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_AST),
+                     "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) "
+                     "which resolves to a wider constant value ({4} bits). "
+                     "Ignoring constant.",
+                     m_derived_ct.GetTypeName(), static_data_member.Name,
+                     member_ct.GetTypeName(), type_width, constant_width);
+          }
+        } else {
+          lldb::BasicType basic_type_enum = member_ct.GetBasicTypeEnumeration();
+          switch (basic_type_enum) {
+          case lldb::eBasicTypeFloat:
+          case lldb::eBasicTypeDouble:
+          case lldb::eBasicTypeLongDouble:
+            if (type_width == constant_width) {
+              TypeSystemClang::SetFloatingInitializerForVariable(
+                  decl, basic_type_enum == lldb::eBasicTypeFloat
+                            ? llvm::APFloat(constant.Value.bitsToFloat())
+                            : llvm::APFloat(constant.Value.bitsToDouble()));
+              decl->setConstexpr(true);
+            } else {
+              LLDB_LOG(
+                  GetLogIfAllCategoriesSet(LIBLLDB_LOG_AST),
+                  "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) "
+                  "which resolves to a constant value of mismatched width "
+                  "({4} bits). Ignoring constant.",
+                  m_derived_ct.GetTypeName(), static_data_member.Name,
+                  member_ct.GetTypeName(), type_width, constant_width);
+            }
+            break;
+          default:
+            break;
+          }
+        }
+        break;
+      }
+    }
+  }
+
   // FIXME: Add a PdbSymUid namespace for field list members and update
   // the m_uid_to_decl map with this decl.
   return Error::success();
@@ -149,7 +213,7 @@ Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
 
   TypeIndex ti(data_member.Type);
   if (!ti.isSimple()) {
-    CVType cvt = m_tpi.getType(ti);
+    CVType cvt = m_index.tpi().getType(ti);
     if (cvt.kind() == LF_BITFIELD) {
       BitFieldRecord bfr;
       llvm::cantFail(TypeDeserializer::deserializeAs<BitFieldRecord>(cvt, bfr));
@@ -187,7 +251,7 @@ Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
                                            OverloadedMethodRecord &overloaded) {
   TypeIndex method_list_idx = overloaded.MethodList;
 
-  CVType method_list_type = m_tpi.getType(method_list_idx);
+  CVType method_list_type = m_index.tpi().getType(method_list_idx);
   assert(method_list_type.kind() == LF_METHODLIST);
 
   MethodOverloadListRecord method_list;

diff  --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
index ed1f8e4e05b1..ae7e47c82fe5 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
@@ -25,6 +25,7 @@ class TagDecl;
 namespace llvm {
 namespace pdb {
 class TpiStream;
+class GlobalsStream;
 }
 } // namespace llvm
 
@@ -33,6 +34,7 @@ class Type;
 class CompilerType;
 namespace npdb {
 class PdbAstBuilder;
+class PdbIndex;
 
 class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks {
   using IndexedBase =
@@ -49,14 +51,14 @@ class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks {
   CompilerType &m_derived_ct;
   clang::TagDecl &m_tag_decl;
   PdbAstBuilder &m_ast_builder;
-  llvm::pdb::TpiStream &m_tpi;
+  PdbIndex &m_index;
   std::vector<IndexedBase> m_bases;
   ClangASTImporter::LayoutInfo m_layout;
 
 public:
   UdtRecordCompleter(PdbTypeSymId id, CompilerType &derived_ct,
                      clang::TagDecl &tag_decl, PdbAstBuilder &ast_builder,
-                     llvm::pdb::TpiStream &tpi);
+                     PdbIndex &index);
 
 #define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
   llvm::Error visitKnownMember(llvm::codeview::CVMemberRecord &CVR,            \

diff  --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
index 112bec41af8b..d87926a6588f 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
@@ -1265,6 +1265,52 @@ void PDBASTParser::AddRecordMembers(
       if (!decl)
         continue;
 
+      // Static constant members may be a const[expr] declaration.
+      // Query the symbol's value as the variable initializer if valid.
+      if (member_comp_type.IsConst()) {
+        auto value = member->getValue();
+        clang::QualType qual_type = decl->getType();
+        unsigned type_width = m_ast.getASTContext().getIntWidth(qual_type);
+        unsigned constant_width = value.getBitWidth();
+
+        if (qual_type->isIntegralOrEnumerationType()) {
+          if (type_width >= constant_width) {
+            TypeSystemClang::SetIntegerInitializerForVariable(
+                decl, value.toAPSInt().extOrTrunc(type_width));
+          } else {
+            LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_AST),
+                     "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) "
+                     "which resolves to a wider constant value ({4} bits). "
+                     "Ignoring constant.",
+                     record_type.GetTypeName(), member_name,
+                     member_comp_type.GetTypeName(), type_width,
+                     constant_width);
+          }
+        } else {
+          switch (member_comp_type.GetBasicTypeEnumeration()) {
+          case lldb::eBasicTypeFloat:
+          case lldb::eBasicTypeDouble:
+          case lldb::eBasicTypeLongDouble:
+            if (type_width == constant_width) {
+              TypeSystemClang::SetFloatingInitializerForVariable(
+                  decl, value.toAPFloat());
+              decl->setConstexpr(true);
+            } else {
+              LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_AST),
+                       "Class '{0}' has a member '{1}' of type '{2}' ({3} "
+                       "bits) which resolves to a constant value of mismatched "
+                       "width ({4} bits). Ignoring constant.",
+                       record_type.GetTypeName(), member_name,
+                       member_comp_type.GetTypeName(), type_width,
+                       constant_width);
+            }
+            break;
+          default:
+            break;
+          }
+        }
+      }
+
       m_uid_to_decl[member->getSymIndexId()] = decl;
 
       break;

diff  --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 972688954c64..fe36d49428a5 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -7316,6 +7316,35 @@ clang::VarDecl *TypeSystemClang::AddVariableToRecordType(
   return var_decl;
 }
 
+void TypeSystemClang::SetIntegerInitializerForVariable(
+    VarDecl *var, const llvm::APInt &init_value) {
+  assert(!var->hasInit() && "variable already initialized");
+
+  clang::ASTContext &ast = var->getASTContext();
+  QualType qt = var->getType();
+  assert(qt->isIntegralOrEnumerationType() &&
+         "only integer or enum types supported");
+  // If the variable is an enum type, take the underlying integer type as
+  // the type of the integer literal.
+  if (const EnumType *enum_type = llvm::dyn_cast<EnumType>(qt.getTypePtr())) {
+    const EnumDecl *enum_decl = enum_type->getDecl();
+    qt = enum_decl->getIntegerType();
+  }
+  var->setInit(IntegerLiteral::Create(ast, init_value, qt.getUnqualifiedType(),
+                                      SourceLocation()));
+}
+
+void TypeSystemClang::SetFloatingInitializerForVariable(
+    clang::VarDecl *var, const llvm::APFloat &init_value) {
+  assert(!var->hasInit() && "variable already initialized");
+
+  clang::ASTContext &ast = var->getASTContext();
+  QualType qt = var->getType();
+  assert(qt->isFloatingType() && "only floating point types supported");
+  var->setInit(FloatingLiteral::Create(
+      ast, init_value, true, qt.getUnqualifiedType(), SourceLocation()));
+}
+
 clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
     lldb::opaque_compiler_type_t type, llvm::StringRef name,
     const char *mangled_name, const CompilerType &method_clang_type,

diff  --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 920d7cb4c23d..9475e4d9f442 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -873,6 +873,24 @@ class TypeSystemClang : public TypeSystem {
                                                  const CompilerType &var_type,
                                                  lldb::AccessType access);
 
+  /// Initializes a variable with an integer value.
+  /// \param var The variable to initialize. Must not already have an
+  ///            initializer and must have an integer or enum type.
+  /// \param init_value The integer value that the variable should be
+  ///                   initialized to. Has to match the bit width of the
+  ///                   variable type.
+  static void SetIntegerInitializerForVariable(clang::VarDecl *var,
+                                               const llvm::APInt &init_value);
+
+  /// Initializes a variable with a floating point value.
+  /// \param var The variable to initialize. Must not already have an
+  ///            initializer and must have a floating point type.
+  /// \param init_value The float value that the variable should be
+  ///                   initialized to.
+  static void
+  SetFloatingInitializerForVariable(clang::VarDecl *var,
+                                    const llvm::APFloat &init_value);
+
   clang::CXXMethodDecl *AddMethodToCXXRecordType(
       lldb::opaque_compiler_type_t type, llvm::StringRef name,
       const char *mangled_name, const CompilerType &method_type,

diff  --git a/lldb/test/Shell/SymbolFile/PDB/Inputs/AstRestoreTest.cpp b/lldb/test/Shell/SymbolFile/PDB/Inputs/AstRestoreTest.cpp
index 8c9e26744d5f..fb20c9d734bd 100644
--- a/lldb/test/Shell/SymbolFile/PDB/Inputs/AstRestoreTest.cpp
+++ b/lldb/test/Shell/SymbolFile/PDB/Inputs/AstRestoreTest.cpp
@@ -3,6 +3,7 @@ namespace N1 {
 
 namespace {
 enum Enum { Enum_0 = 1, Enum_1 = 2, Enum_2 = 4, Enum_3 = 8 };
+enum class ScopedEnum { Enum_0 = 1, Enum_1 = 2, Enum_2 = 4, Enum_3 = 8 };
 }
 
 Enum Global = Enum_3;
@@ -22,6 +23,13 @@ class Class : public Base {
   const Enum m_ce;
 
   static int ClassStatic;
+  static const int ClassStaticConst = 8;
+  static constexpr int ClassStaticConstexpr = 9;
+  static constexpr float ClassStaticConstexprFloat = 10.f;
+  static constexpr double ClassStaticConstexprDouble = 11.0;
+  static constexpr long double ClassStaticConstexprLongDouble = 12.0;
+  static const Enum ClassStaticConstEnum = Enum_3;
+  static const ScopedEnum ClassStaticConstScopedEnum = ScopedEnum::Enum_2;
 
 private:
   struct Inner {

diff  --git a/lldb/test/Shell/SymbolFile/PDB/ast-restore.test b/lldb/test/Shell/SymbolFile/PDB/ast-restore.test
index 14ec0d52f2ed..2473bb1d66f5 100644
--- a/lldb/test/Shell/SymbolFile/PDB/ast-restore.test
+++ b/lldb/test/Shell/SymbolFile/PDB/ast-restore.test
@@ -4,7 +4,8 @@ RUN: env LLDB_USE_NATIVE_PDB_READER=0 lldb-test symbols -dump-ast %t.exe | FileC
 RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=ENUM %s
 RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=GLOBAL %s
 RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=BASE %s
-RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=CLASS %s
+RUN: env LLDB_USE_NATIVE_PDB_READER=0 lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=CLASS %s
+RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=CLASS %s
 RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=INNER %s
 RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=TEMPLATE %s
 RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=FOO %s
@@ -46,6 +47,13 @@ CLASS:     namespace N1 {
 CLASS:         class Class : public N0::N1::Base {
 CLASS-DAG:             const N0::N1::(anonymous namespace)::Enum m_ce;
 CLASS-DAG:             static int ClassStatic;
+CLASS-DAG:             static const int ClassStaticConst = 8;
+CLASS-DAG:             static const int ClassStaticConstexpr = 9;
+CLASS-DAG:             static constexpr float ClassStaticConstexprFloat = 10.F;
+CLASS-DAG:             static constexpr double ClassStaticConstexprDouble = 11.;
+CLASS-DAG:             static constexpr double ClassStaticConstexprLongDouble = 12.;
+CLASS-DAG:             static const N0::N1::(anonymous namespace)::Enum ClassStaticConstEnum = 8;
+CLASS-DAG:             static const N0::N1::(anonymous namespace)::ScopedEnum ClassStaticConstScopedEnum = 4;
 CLASS-DAG:             N0::N1::Class::Inner m_inner;
 CLASS-DAG:             {{(inline )?}}Class(N0::N1::(anonymous namespace)::Enum);
 CLASS-DAG:             static {{(inline )?}}int StaticFunc(const N0::N1::Class &);

diff  --git a/llvm/include/llvm/DebugInfo/PDB/PDBTypes.h b/llvm/include/llvm/DebugInfo/PDB/PDBTypes.h
index 66c842336e90..e7c2ded1bee1 100644
--- a/llvm/include/llvm/DebugInfo/PDB/PDBTypes.h
+++ b/llvm/include/llvm/DebugInfo/PDB/PDBTypes.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_DEBUGINFO_PDB_PDBTYPES_H
 #define LLVM_DEBUGINFO_PDB_PDBTYPES_H
 
+#include "llvm/ADT/APFloat.h"
 #include "llvm/DebugInfo/CodeView/CodeView.h"
 #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
 #include "llvm/DebugInfo/PDB/IPDBFrameData.h"
@@ -464,6 +465,88 @@ struct Variant {
     char *String;
   } Value;
 
+  bool isIntegralType() const {
+    switch (Type) {
+    case Bool:
+    case Int8:
+    case Int16:
+    case Int32:
+    case Int64:
+    case UInt8:
+    case UInt16:
+    case UInt32:
+    case UInt64:
+      return true;
+    default:
+      return false;
+    }
+  }
+
+#define VARIANT_WIDTH(Enum, NumBits)                                           \
+  case PDB_VariantType::Enum:                                                  \
+    return NumBits;
+
+  unsigned getBitWidth() const {
+    switch (Type) {
+      VARIANT_WIDTH(Bool, 1u)
+      VARIANT_WIDTH(Int8, 8u)
+      VARIANT_WIDTH(Int16, 16u)
+      VARIANT_WIDTH(Int32, 32u)
+      VARIANT_WIDTH(Int64, 64u)
+      VARIANT_WIDTH(Single, 32u)
+      VARIANT_WIDTH(Double, 64u)
+      VARIANT_WIDTH(UInt8, 8u)
+      VARIANT_WIDTH(UInt16, 16u)
+      VARIANT_WIDTH(UInt32, 32u)
+      VARIANT_WIDTH(UInt64, 64u)
+    default:
+      assert(false && "Variant::toAPSInt called on non-numeric type");
+      return 0u;
+    }
+  }
+
+#undef VARIANT_WIDTH
+
+#define VARIANT_APSINT(Enum, NumBits, IsUnsigned)                              \
+  case PDB_VariantType::Enum:                                                  \
+    return APSInt(APInt(NumBits, Value.Enum), IsUnsigned);
+
+  APSInt toAPSInt() const {
+    switch (Type) {
+      VARIANT_APSINT(Bool, 1u, true)
+      VARIANT_APSINT(Int8, 8u, false)
+      VARIANT_APSINT(Int16, 16u, false)
+      VARIANT_APSINT(Int32, 32u, false)
+      VARIANT_APSINT(Int64, 64u, false)
+      VARIANT_APSINT(UInt8, 8u, true)
+      VARIANT_APSINT(UInt16, 16u, true)
+      VARIANT_APSINT(UInt32, 32u, true)
+      VARIANT_APSINT(UInt64, 64u, true)
+    default:
+      assert(false && "Variant::toAPSInt called on non-integral type");
+      return APSInt();
+    }
+  }
+
+#undef VARIANT_APSINT
+
+  APFloat toAPFloat() const {
+    // Float constants may be tagged as integers.
+    switch (Type) {
+    case PDB_VariantType::Single:
+    case PDB_VariantType::UInt32:
+    case PDB_VariantType::Int32:
+      return APFloat(Value.Single);
+    case PDB_VariantType::Double:
+    case PDB_VariantType::UInt64:
+    case PDB_VariantType::Int64:
+      return APFloat(Value.Double);
+    default:
+      assert(false && "Variant::toAPFloat called on non-floating-point type");
+      return APFloat::getZero(APFloat::IEEEsingle());
+    }
+  }
+
 #define VARIANT_EQUAL_CASE(Enum)                                               \
   case PDB_VariantType::Enum:                                                  \
     return Value.Enum == Other.Value.Enum;


        


More information about the lldb-commits mailing list