diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/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(); diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h --- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h +++ b/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 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/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp --- 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 @@ 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(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 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(result.second, + constant)); + + uint32_t count; + bool is_complex; + if (member_ct.IsFloatingPointType(count, is_complex)) { + switch (ClangUtil::GetQualType(member_ct) + ->castAs() + ->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(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; diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp --- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/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; diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/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, diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/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, diff --git a/lldb/test/Shell/SymbolFile/PDB/Inputs/AstRestoreTest.cpp b/lldb/test/Shell/SymbolFile/PDB/Inputs/AstRestoreTest.cpp --- a/lldb/test/Shell/SymbolFile/PDB/Inputs/AstRestoreTest.cpp +++ b/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 { diff --git a/lldb/test/Shell/SymbolFile/PDB/ast-restore.test b/lldb/test/Shell/SymbolFile/PDB/ast-restore.test --- a/lldb/test/Shell/SymbolFile/PDB/ast-restore.test +++ b/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 &); diff --git a/llvm/include/llvm/DebugInfo/PDB/PDBTypes.h b/llvm/include/llvm/DebugInfo/PDB/PDBTypes.h --- 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,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;