mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-13 03:12:46 +00:00
[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
This commit is contained in:
parent
2c061998b5
commit
895529cfd8
@ -681,7 +681,7 @@ bool PdbAstBuilder::CompleteTagDecl(clang::TagDecl &tag) {
|
|||||||
// Visit all members of this class, then perform any finalization necessary
|
// Visit all members of this class, then perform any finalization necessary
|
||||||
// to complete the class.
|
// to complete the class.
|
||||||
CompilerType ct = ToCompilerType(tag_qt);
|
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 =
|
auto error =
|
||||||
llvm::codeview::visitMemberRecordStream(field_list_cvt.data(), completer);
|
llvm::codeview::visitMemberRecordStream(field_list_cvt.data(), completer);
|
||||||
completer.complete();
|
completer.complete();
|
||||||
|
@ -6,14 +6,17 @@
|
|||||||
#include "PdbUtil.h"
|
#include "PdbUtil.h"
|
||||||
|
|
||||||
#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
|
#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
|
||||||
|
#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
|
||||||
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
|
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
|
||||||
#include "lldb/Symbol/Type.h"
|
#include "lldb/Symbol/Type.h"
|
||||||
#include "lldb/Utility/LLDBAssert.h"
|
#include "lldb/Utility/LLDBAssert.h"
|
||||||
#include "lldb/lldb-enumerations.h"
|
#include "lldb/lldb-enumerations.h"
|
||||||
#include "lldb/lldb-forward.h"
|
#include "lldb/lldb-forward.h"
|
||||||
|
|
||||||
|
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeIndex.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/Native/TpiStream.h"
|
||||||
#include "llvm/DebugInfo/PDB/PDBTypes.h"
|
#include "llvm/DebugInfo/PDB/PDBTypes.h"
|
||||||
|
|
||||||
@ -29,10 +32,10 @@ UdtRecordCompleter::UdtRecordCompleter(PdbTypeSymId id,
|
|||||||
CompilerType &derived_ct,
|
CompilerType &derived_ct,
|
||||||
clang::TagDecl &tag_decl,
|
clang::TagDecl &tag_decl,
|
||||||
PdbAstBuilder &ast_builder,
|
PdbAstBuilder &ast_builder,
|
||||||
TpiStream &tpi)
|
PdbIndex &index)
|
||||||
: m_id(id), m_derived_ct(derived_ct), m_tag_decl(tag_decl),
|
: m_id(id), m_derived_ct(derived_ct), m_tag_decl(tag_decl),
|
||||||
m_ast_builder(ast_builder), m_tpi(tpi) {
|
m_ast_builder(ast_builder), m_index(index) {
|
||||||
CVType cvt = m_tpi.getType(m_id.index);
|
CVType cvt = m_index.tpi().getType(m_id.index);
|
||||||
switch (cvt.kind()) {
|
switch (cvt.kind()) {
|
||||||
case LF_ENUM:
|
case LF_ENUM:
|
||||||
llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er));
|
llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er));
|
||||||
@ -55,7 +58,7 @@ clang::QualType UdtRecordCompleter::AddBaseClassForTypeIndex(
|
|||||||
PdbTypeSymId type_id(ti);
|
PdbTypeSymId type_id(ti);
|
||||||
clang::QualType qt = m_ast_builder.GetOrCreateType(type_id);
|
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 =
|
std::unique_ptr<clang::CXXBaseSpecifier> base_spec =
|
||||||
m_ast_builder.clang().CreateBaseClassSpecifier(
|
m_ast_builder.clang().CreateBaseClassSpecifier(
|
||||||
@ -128,9 +131,70 @@ Error UdtRecordCompleter::visitKnownMember(
|
|||||||
|
|
||||||
lldb::AccessType access =
|
lldb::AccessType access =
|
||||||
TranslateMemberAccess(static_data_member.getAccess());
|
TranslateMemberAccess(static_data_member.getAccess());
|
||||||
TypeSystemClang::AddVariableToRecordType(
|
auto decl = TypeSystemClang::AddVariableToRecordType(
|
||||||
m_derived_ct, static_data_member.Name, member_ct, access);
|
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
|
// FIXME: Add a PdbSymUid namespace for field list members and update
|
||||||
// the m_uid_to_decl map with this decl.
|
// the m_uid_to_decl map with this decl.
|
||||||
return Error::success();
|
return Error::success();
|
||||||
@ -149,7 +213,7 @@ Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
|
|||||||
|
|
||||||
TypeIndex ti(data_member.Type);
|
TypeIndex ti(data_member.Type);
|
||||||
if (!ti.isSimple()) {
|
if (!ti.isSimple()) {
|
||||||
CVType cvt = m_tpi.getType(ti);
|
CVType cvt = m_index.tpi().getType(ti);
|
||||||
if (cvt.kind() == LF_BITFIELD) {
|
if (cvt.kind() == LF_BITFIELD) {
|
||||||
BitFieldRecord bfr;
|
BitFieldRecord bfr;
|
||||||
llvm::cantFail(TypeDeserializer::deserializeAs<BitFieldRecord>(cvt, bfr));
|
llvm::cantFail(TypeDeserializer::deserializeAs<BitFieldRecord>(cvt, bfr));
|
||||||
@ -187,7 +251,7 @@ Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
|
|||||||
OverloadedMethodRecord &overloaded) {
|
OverloadedMethodRecord &overloaded) {
|
||||||
TypeIndex method_list_idx = overloaded.MethodList;
|
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);
|
assert(method_list_type.kind() == LF_METHODLIST);
|
||||||
|
|
||||||
MethodOverloadListRecord method_list;
|
MethodOverloadListRecord method_list;
|
||||||
|
@ -25,6 +25,7 @@ class TagDecl;
|
|||||||
namespace llvm {
|
namespace llvm {
|
||||||
namespace pdb {
|
namespace pdb {
|
||||||
class TpiStream;
|
class TpiStream;
|
||||||
|
class GlobalsStream;
|
||||||
}
|
}
|
||||||
} // namespace llvm
|
} // namespace llvm
|
||||||
|
|
||||||
@ -33,6 +34,7 @@ class Type;
|
|||||||
class CompilerType;
|
class CompilerType;
|
||||||
namespace npdb {
|
namespace npdb {
|
||||||
class PdbAstBuilder;
|
class PdbAstBuilder;
|
||||||
|
class PdbIndex;
|
||||||
|
|
||||||
class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks {
|
class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks {
|
||||||
using IndexedBase =
|
using IndexedBase =
|
||||||
@ -49,14 +51,14 @@ class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks {
|
|||||||
CompilerType &m_derived_ct;
|
CompilerType &m_derived_ct;
|
||||||
clang::TagDecl &m_tag_decl;
|
clang::TagDecl &m_tag_decl;
|
||||||
PdbAstBuilder &m_ast_builder;
|
PdbAstBuilder &m_ast_builder;
|
||||||
llvm::pdb::TpiStream &m_tpi;
|
PdbIndex &m_index;
|
||||||
std::vector<IndexedBase> m_bases;
|
std::vector<IndexedBase> m_bases;
|
||||||
ClangASTImporter::LayoutInfo m_layout;
|
ClangASTImporter::LayoutInfo m_layout;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UdtRecordCompleter(PdbTypeSymId id, CompilerType &derived_ct,
|
UdtRecordCompleter(PdbTypeSymId id, CompilerType &derived_ct,
|
||||||
clang::TagDecl &tag_decl, PdbAstBuilder &ast_builder,
|
clang::TagDecl &tag_decl, PdbAstBuilder &ast_builder,
|
||||||
llvm::pdb::TpiStream &tpi);
|
PdbIndex &index);
|
||||||
|
|
||||||
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
|
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
|
||||||
llvm::Error visitKnownMember(llvm::codeview::CVMemberRecord &CVR, \
|
llvm::Error visitKnownMember(llvm::codeview::CVMemberRecord &CVR, \
|
||||||
|
@ -1265,6 +1265,52 @@ void PDBASTParser::AddRecordMembers(
|
|||||||
if (!decl)
|
if (!decl)
|
||||||
continue;
|
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;
|
m_uid_to_decl[member->getSymIndexId()] = decl;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -7316,6 +7316,35 @@ clang::VarDecl *TypeSystemClang::AddVariableToRecordType(
|
|||||||
return var_decl;
|
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(
|
clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
|
||||||
lldb::opaque_compiler_type_t type, llvm::StringRef name,
|
lldb::opaque_compiler_type_t type, llvm::StringRef name,
|
||||||
const char *mangled_name, const CompilerType &method_clang_type,
|
const char *mangled_name, const CompilerType &method_clang_type,
|
||||||
|
@ -873,6 +873,24 @@ public:
|
|||||||
const CompilerType &var_type,
|
const CompilerType &var_type,
|
||||||
lldb::AccessType access);
|
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(
|
clang::CXXMethodDecl *AddMethodToCXXRecordType(
|
||||||
lldb::opaque_compiler_type_t type, llvm::StringRef name,
|
lldb::opaque_compiler_type_t type, llvm::StringRef name,
|
||||||
const char *mangled_name, const CompilerType &method_type,
|
const char *mangled_name, const CompilerType &method_type,
|
||||||
|
@ -3,6 +3,7 @@ namespace N1 {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
enum Enum { Enum_0 = 1, Enum_1 = 2, Enum_2 = 4, Enum_3 = 8 };
|
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;
|
Enum Global = Enum_3;
|
||||||
@ -22,6 +23,13 @@ public:
|
|||||||
const Enum m_ce;
|
const Enum m_ce;
|
||||||
|
|
||||||
static int ClassStatic;
|
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:
|
private:
|
||||||
struct Inner {
|
struct Inner {
|
||||||
|
@ -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: 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=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=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=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=TEMPLATE %s
|
||||||
RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=FOO %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: class Class : public N0::N1::Base {
|
||||||
CLASS-DAG: const N0::N1::(anonymous namespace)::Enum m_ce;
|
CLASS-DAG: const N0::N1::(anonymous namespace)::Enum m_ce;
|
||||||
CLASS-DAG: static int ClassStatic;
|
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: N0::N1::Class::Inner m_inner;
|
||||||
CLASS-DAG: {{(inline )?}}Class(N0::N1::(anonymous namespace)::Enum);
|
CLASS-DAG: {{(inline )?}}Class(N0::N1::(anonymous namespace)::Enum);
|
||||||
CLASS-DAG: static {{(inline )?}}int StaticFunc(const N0::N1::Class &);
|
CLASS-DAG: static {{(inline )?}}int StaticFunc(const N0::N1::Class &);
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#ifndef LLVM_DEBUGINFO_PDB_PDBTYPES_H
|
#ifndef LLVM_DEBUGINFO_PDB_PDBTYPES_H
|
||||||
#define 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/CodeView/CodeView.h"
|
||||||
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
|
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
|
||||||
#include "llvm/DebugInfo/PDB/IPDBFrameData.h"
|
#include "llvm/DebugInfo/PDB/IPDBFrameData.h"
|
||||||
@ -464,6 +465,88 @@ struct Variant {
|
|||||||
char *String;
|
char *String;
|
||||||
} Value;
|
} 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) \
|
#define VARIANT_EQUAL_CASE(Enum) \
|
||||||
case PDB_VariantType::Enum: \
|
case PDB_VariantType::Enum: \
|
||||||
return Value.Enum == Other.Value.Enum;
|
return Value.Enum == Other.Value.Enum;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user