[LLDB] Fix printing a static bool struct member when using "image lookup -t"

Fixes #58135

Somehow lldb was able to print the member on its own but when we try
to print the whole type found by "image lookup -t" lldb would crash.

This is because we'd encoded the initial value of the member as an integer.
Which isn't the end of the world because bool is integral for C++.
However, clang has a special AST node to handle literal bool and it
expected us to use that instead.

This adds a new codepath to handle static bool which uses cxxBoolLiteralExpr
and we get the member printed as you'd expect.

For testing I added a struct with just the bool because trying to print
all of "A" crashes as well. Presumably because one of the other member's
types isn't handled properly either.

So for now I just added the bool case, we can merge it with A later.

Reviewed By: aeubanks

Differential Revision: https://reviews.llvm.org/D135169
This commit is contained in:
David Spickett 2022-10-04 14:56:12 +00:00
parent 7b442b07f2
commit 02c1c93948
8 changed files with 58 additions and 1 deletions

View File

@ -121,6 +121,8 @@ public:
bool IsIntegerOrEnumerationType(bool &is_signed) const;
bool IsBooleanType() const;
bool IsPolymorphicClass() const;
/// \param target_type Can pass nullptr.

View File

@ -178,6 +178,8 @@ public:
return false;
}
virtual bool IsBooleanType(lldb::opaque_compiler_type_t type) = 0;
virtual bool IsScopedEnumerationType(lldb::opaque_compiler_type_t type) = 0;
virtual bool IsPossibleDynamicType(lldb::opaque_compiler_type_t type,

View File

@ -2720,6 +2720,7 @@ void DWARFASTParserClang::ParseSingleMember(
// TODO: Support float/double static members as well.
if (!attrs.const_value_form || !ct.IsIntegerOrEnumerationType(unused))
return;
llvm::Expected<llvm::APInt> const_value_or_err =
ExtractIntFromFormValue(ct, *attrs.const_value_form);
if (!const_value_or_err) {
@ -2728,7 +2729,13 @@ void DWARFASTParserClang::ParseSingleMember(
v->getQualifiedNameAsString());
return;
}
TypeSystemClang::SetIntegerInitializerForVariable(v, *const_value_or_err);
if (ct.IsBooleanType())
TypeSystemClang::SetBoolInitializerForVariable(
v, !const_value_or_err->isZero());
else
TypeSystemClang::SetIntegerInitializerForVariable(v,
*const_value_or_err);
}
return;
}

View File

@ -3224,6 +3224,20 @@ bool TypeSystemClang::IsIntegerType(lldb::opaque_compiler_type_t type,
return false;
}
bool TypeSystemClang::IsBooleanType(lldb::opaque_compiler_type_t type) {
if (!type)
return false;
clang::QualType qual_type(GetCanonicalQualType(type));
const clang::BuiltinType *builtin_type =
llvm::dyn_cast<clang::BuiltinType>(qual_type->getCanonicalTypeInternal());
if (!builtin_type)
return false;
return builtin_type->isBooleanType();
}
bool TypeSystemClang::IsEnumerationType(lldb::opaque_compiler_type_t type,
bool &is_signed) {
if (type) {
@ -7574,6 +7588,18 @@ clang::VarDecl *TypeSystemClang::AddVariableToRecordType(
return var_decl;
}
void TypeSystemClang::SetBoolInitializerForVariable(VarDecl *var, bool value) {
assert(!var->hasInit() && "variable already initialized");
QualType qt = var->getType();
assert(qt->isSpecificBuiltinType(BuiltinType::Bool) &&
"only boolean supported");
clang::ASTContext &ast = var->getASTContext();
var->setInit(CXXBoolLiteralExpr::Create(ast, value, qt.getUnqualifiedType(),
SourceLocation()));
}
void TypeSystemClang::SetIntegerInitializerForVariable(
VarDecl *var, const llvm::APInt &init_value) {
assert(!var->hasInit() && "variable already initialized");

View File

@ -592,6 +592,8 @@ public:
bool IsEnumerationType(lldb::opaque_compiler_type_t type,
bool &is_signed) override;
bool IsBooleanType(lldb::opaque_compiler_type_t type) override;
bool IsScopedEnumerationType(lldb::opaque_compiler_type_t type) override;
static bool IsObjCClassType(const CompilerType &type);
@ -860,6 +862,8 @@ public:
static void SetIntegerInitializerForVariable(clang::VarDecl *var,
const llvm::APInt &init_value);
static void SetBoolInitializerForVariable(clang::VarDecl *var, bool 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.

View File

@ -154,6 +154,12 @@ bool CompilerType::IsIntegerOrEnumerationType(bool &is_signed) const {
return IsIntegerType(is_signed) || IsEnumerationType(is_signed);
}
bool CompilerType::IsBooleanType() const {
if (IsValid())
return m_type_system->IsBooleanType(m_type);
return false;
}
bool CompilerType::IsPointerType(CompilerType *pointee_type) const {
if (IsValid()) {
return m_type_system->IsPointerType(m_type, pointee_type);

View File

@ -32,6 +32,11 @@ class TestCase(TestBase):
# Test a bool member.
self.expect_expr("A::bool_val", result_value="true")
# Test a bool member when printing the struct it is a member of.
# TODO: replace this with printing struct A, once doing so doesn't crash lldb.
self.expect("image lookup -t StaticBoolStruct",
substrs=["static const bool value = false;"])
# Test that minimum and maximum values for each data type are right.
self.expect_expr("A::char_max == char_max", result_value="true")
self.expect_expr("A::uchar_max == uchar_max", result_value="true")

View File

@ -79,8 +79,13 @@ struct ClassWithEnumAlias {
ScopedEnum::scoped_enum_case1;
};
struct StaticBoolStruct {
static const bool value = false;
};
int main() {
A a;
StaticBoolStruct sbs;
auto char_max = A::char_max;
auto uchar_max = A::uchar_max;