jackoalan created this revision.
jackoalan added reviewers: aleksandr.urakov, jasonmolenda, zturner.
jackoalan added a project: LLDB.
Herald added a reviewer: jdoerfert.
Herald added subscribers: llvm-commits, lldb-commits, sstefan1.
Herald added a project: LLVM.

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.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D82160

Files:
  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

Index: llvm/include/llvm/DebugInfo/PDB/PDBTypes.h
===================================================================
--- llvm/include/llvm/DebugInfo/PDB/PDBTypes.h
+++ 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,73 @@
     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;
+    }
+  }
+
+  bool isFloatingPointType() const {
+    switch (Type) {
+    case Single:
+    case Double:
+      return true;
+    default:
+      return false;
+    }
+  }
+
+#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, 1, true)
+      VARIANT_APSINT(Int8, 8, false)
+      VARIANT_APSINT(Int16, 16, false)
+      VARIANT_APSINT(Int32, 32, false)
+      VARIANT_APSINT(Int64, 64, false)
+      VARIANT_APSINT(UInt8, 8, true)
+      VARIANT_APSINT(UInt16, 16, true)
+      VARIANT_APSINT(UInt32, 32, true)
+      VARIANT_APSINT(UInt64, 64, 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;
Index: lldb/test/Shell/SymbolFile/PDB/ast-restore.test
===================================================================
--- lldb/test/Shell/SymbolFile/PDB/ast-restore.test
+++ lldb/test/Shell/SymbolFile/PDB/ast-restore.test
@@ -46,6 +46,9 @@
 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 constexpr int ClassStaticConstexpr = 8;
+CLASS-DAG:             static constexpr float ClassStaticConstexprFloat = 9.F;
+CLASS-DAG:             static constexpr double ClassStaticConstexprDouble = 10.;
 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 &);
Index: lldb/test/Shell/SymbolFile/PDB/Inputs/AstRestoreTest.cpp
===================================================================
--- lldb/test/Shell/SymbolFile/PDB/Inputs/AstRestoreTest.cpp
+++ lldb/test/Shell/SymbolFile/PDB/Inputs/AstRestoreTest.cpp
@@ -22,6 +22,9 @@
   const Enum m_ce;
 
   static int ClassStatic;
+  static constexpr int ClassStaticConstexpr = 8;
+  static constexpr float ClassStaticConstexprFloat = 9.f;
+  static constexpr double ClassStaticConstexprDouble = 10.0;
 
 private:
   struct Inner {
Index: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
===================================================================
--- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -873,6 +873,11 @@
                                                  const CompilerType &var_type,
                                                  lldb::AccessType access);
 
+  static void AddConstexprInitializerToVariable(clang::VarDecl *var_decl,
+                                                llvm::APSInt value);
+  static void AddConstexprInitializerToVariable(clang::VarDecl *var_decl,
+                                                llvm::APFloat value);
+
   clang::CXXMethodDecl *AddMethodToCXXRecordType(
       lldb::opaque_compiler_type_t type, llvm::StringRef name,
       const char *mangled_name, const CompilerType &method_type,
Index: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
===================================================================
--- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -7313,6 +7313,24 @@
   return var_decl;
 }
 
+void TypeSystemClang::AddConstexprInitializerToVariable(
+    clang::VarDecl *var_decl, llvm::APSInt value) {
+  uint64_t num_bits =
+      var_decl->getASTContext().getTypeSize(var_decl->getType());
+  var_decl->setInit(clang::IntegerLiteral::Create(
+      var_decl->getASTContext(), value.extOrTrunc(num_bits),
+      var_decl->getType(), clang::SourceLocation()));
+  var_decl->setConstexpr(true);
+}
+
+void TypeSystemClang::AddConstexprInitializerToVariable(
+    clang::VarDecl *var_decl, llvm::APFloat value) {
+  var_decl->setInit(clang::FloatingLiteral::Create(
+      var_decl->getASTContext(), value, true, var_decl->getType(),
+      clang::SourceLocation()));
+  var_decl->setConstexpr(true);
+}
+
 clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
     lldb::opaque_compiler_type_t type, llvm::StringRef name,
     const char *mangled_name, const CompilerType &method_clang_type,
Index: lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
+++ lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
@@ -1265,6 +1265,23 @@
       if (!decl)
         continue;
 
+      // Static constant members may be a constexpr declaration.
+      // Query the symbol's value as the variable initializer if valid.
+      if (member_comp_type.IsConst()) {
+        auto value = member->getValue();
+        uint32_t count;
+        bool is_complex;
+        if (value.isFloatingPointType() ||
+            (value.isIntegralType() &&
+             member_comp_type.IsFloatingPointType(count, is_complex))) {
+          TypeSystemClang::AddConstexprInitializerToVariable(decl,
+                                                             value.toAPFloat());
+        } else if (value.isIntegralType()) {
+          TypeSystemClang::AddConstexprInitializerToVariable(decl,
+                                                             value.toAPSInt());
+        }
+      }
+
       m_uid_to_decl[member->getSymIndexId()] = decl;
 
       break;
Index: lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
+++ lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
@@ -25,6 +25,7 @@
 namespace llvm {
 namespace pdb {
 class TpiStream;
+class GlobalsStream;
 }
 } // namespace llvm
 
@@ -33,6 +34,7 @@
 class CompilerType;
 namespace npdb {
 class PdbAstBuilder;
+class PdbIndex;
 
 class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks {
   using IndexedBase =
@@ -49,14 +51,14 @@
   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,            \
Index: lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
+++ 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 @@
                                        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 @@
   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,50 @@
 
   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 constexpr declaration.
+  // Query the symbol's value as the variable initializer if valid.
+  if (member_ct.IsConst()) {
+    auto 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));
+
+        uint32_t count;
+        bool is_complex;
+        if (member_ct.IsFloatingPointType(count, is_complex)) {
+          switch (ClangUtil::GetQualType(member_ct)
+                      ->castAs<clang::BuiltinType>()
+                      ->getKind()) {
+          case clang::BuiltinType::Float:
+            TypeSystemClang::AddConstexprInitializerToVariable(
+                decl, llvm::APFloat(constant.Value.bitsToFloat()));
+            break;
+          case clang::BuiltinType::Double:
+            TypeSystemClang::AddConstexprInitializerToVariable(
+                decl, llvm::APFloat(constant.Value.bitsToDouble()));
+            break;
+          default:
+            assert(false && "Unsupported builtin float type");
+          }
+        } else {
+          TypeSystemClang::AddConstexprInitializerToVariable(decl,
+                                                             constant.Value);
+        }
+
+        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 +193,7 @@
 
   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 +231,7 @@
                                            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;
Index: lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
+++ lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -681,7 +681,7 @@
   // 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();
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
  • [Lldb-commits] [PATCH] D... Jack Andersen via Phabricator via lldb-commits

Reply via email to