mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 22:00:10 +00:00
Revert "[lldb] Add support for using integral const static data members in the expression evaluator"
This reverts commit 486787210d
.
This broke the windows lldb bot: https://lab.llvm.org/buildbot/#/builders/83/builds/21186
This commit is contained in:
parent
64d63f4823
commit
c3a28e8a99
@ -197,27 +197,6 @@ bool ASTResultSynthesizer::SynthesizeObjCMethodResult(
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Returns true if LLDB can take the address of the given lvalue for the sake
|
||||
/// of capturing the expression result. Returns false if LLDB should instead
|
||||
/// store the expression result in a result variable.
|
||||
static bool CanTakeAddressOfLValue(const Expr *lvalue_expr) {
|
||||
assert(lvalue_expr->getValueKind() == VK_LValue &&
|
||||
"lvalue_expr not a lvalue");
|
||||
|
||||
QualType qt = lvalue_expr->getType();
|
||||
// If the lvalue has const-qualified non-volatile integral or enum type, then
|
||||
// the underlying value might come from a const static data member as
|
||||
// described in C++11 [class.static.data]p3. If that's the case, then the
|
||||
// value might not have an address if the user didn't also define the member
|
||||
// in a namespace scope. Taking the address would cause that LLDB later fails
|
||||
// to link the expression, so those lvalues should be stored in a result
|
||||
// variable.
|
||||
if (qt->isIntegralOrEnumerationType() && qt.isConstQualified() &&
|
||||
!qt.isVolatileQualified())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body,
|
||||
DeclContext *DC) {
|
||||
Log *log = GetLog(LLDBLog::Expressions);
|
||||
@ -286,10 +265,6 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body,
|
||||
// - During dematerialization, $0 is marked up as a load address with value
|
||||
// equal to the contents of the structure entry.
|
||||
//
|
||||
// - Note: if we cannot take an address of the resulting Lvalue (e.g. it's
|
||||
// a static const member without an out-of-class definition), then we
|
||||
// follow the Rvalue route.
|
||||
//
|
||||
// For Rvalues
|
||||
//
|
||||
// - In AST result synthesis the expression E is transformed into an
|
||||
@ -329,7 +304,7 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body,
|
||||
|
||||
clang::VarDecl *result_decl = nullptr;
|
||||
|
||||
if (is_lvalue && CanTakeAddressOfLValue(last_expr)) {
|
||||
if (is_lvalue) {
|
||||
IdentifierInfo *result_ptr_id;
|
||||
|
||||
if (expr_type->isFunctionType())
|
||||
|
@ -2390,7 +2390,6 @@ struct MemberAttributes {
|
||||
uint64_t data_bit_offset = UINT64_MAX;
|
||||
AccessType accessibility = eAccessNone;
|
||||
llvm::Optional<uint64_t> byte_size;
|
||||
llvm::Optional<DWARFFormValue> const_value_form;
|
||||
DWARFFormValue encoding_form;
|
||||
/// Indicates the byte offset of the word from the base address of the
|
||||
/// structure.
|
||||
@ -2437,9 +2436,6 @@ MemberAttributes::MemberAttributes(const DWARFDIE &die,
|
||||
case DW_AT_byte_size:
|
||||
byte_size = form_value.Unsigned();
|
||||
break;
|
||||
case DW_AT_const_value:
|
||||
const_value_form = form_value;
|
||||
break;
|
||||
case DW_AT_data_bit_offset:
|
||||
data_bit_offset = form_value.Unsigned();
|
||||
break;
|
||||
@ -2591,65 +2587,12 @@ void DWARFASTParserClang::ParseObjCProperty(
|
||||
propAttrs.prop_getter_name, propAttrs.prop_attributes, &metadata));
|
||||
}
|
||||
|
||||
llvm::Expected<llvm::APInt> DWARFASTParserClang::ExtractIntFromFormValue(
|
||||
const CompilerType &int_type, const DWARFFormValue &form_value) const {
|
||||
clang::QualType qt = ClangUtil::GetQualType(int_type);
|
||||
assert(qt->isIntegralOrEnumerationType());
|
||||
TypeSystemClang &ts = *llvm::cast<TypeSystemClang>(int_type.GetTypeSystem());
|
||||
clang::ASTContext &ast = ts.getASTContext();
|
||||
|
||||
const unsigned type_bits = ast.getIntWidth(qt);
|
||||
const bool is_unsigned = qt->isUnsignedIntegerType();
|
||||
|
||||
// The maximum int size supported at the moment by this function. Limited
|
||||
// by the uint64_t return type of DWARFFormValue::Signed/Unsigned.
|
||||
constexpr std::size_t max_bit_size = 64;
|
||||
|
||||
// For values bigger than 64 bit (e.g. __int128_t values),
|
||||
// DWARFFormValue's Signed/Unsigned functions will return wrong results so
|
||||
// emit an error for now.
|
||||
if (type_bits > max_bit_size) {
|
||||
auto msg = llvm::formatv("Can only parse integers with up to {0} bits, but "
|
||||
"given integer has {1} bits.",
|
||||
max_bit_size, type_bits);
|
||||
return llvm::createStringError(llvm::inconvertibleErrorCode(), msg.str());
|
||||
}
|
||||
|
||||
// Construct an APInt with the maximum bit size and the given integer.
|
||||
llvm::APInt result(max_bit_size, form_value.Unsigned(), !is_unsigned);
|
||||
|
||||
// Calculate how many bits are required to represent the input value.
|
||||
// For unsigned types, take the number of active bits in the APInt.
|
||||
// For signed types, ask APInt how many bits are required to represent the
|
||||
// signed integer.
|
||||
const unsigned required_bits =
|
||||
is_unsigned ? result.getActiveBits() : result.getMinSignedBits();
|
||||
|
||||
// If the input value doesn't fit into the integer type, return an error.
|
||||
if (required_bits > type_bits) {
|
||||
std::string value_as_str = is_unsigned
|
||||
? std::to_string(form_value.Unsigned())
|
||||
: std::to_string(form_value.Signed());
|
||||
auto msg = llvm::formatv("Can't store {0} value {1} in integer with {2} "
|
||||
"bits.",
|
||||
(is_unsigned ? "unsigned" : "signed"),
|
||||
value_as_str, type_bits);
|
||||
return llvm::createStringError(llvm::inconvertibleErrorCode(), msg.str());
|
||||
}
|
||||
|
||||
// Trim the result to the bit width our the int type.
|
||||
if (result.getBitWidth() > type_bits)
|
||||
result = result.trunc(type_bits);
|
||||
return result;
|
||||
}
|
||||
|
||||
void DWARFASTParserClang::ParseSingleMember(
|
||||
const DWARFDIE &die, const DWARFDIE &parent_die,
|
||||
const lldb_private::CompilerType &class_clang_type,
|
||||
lldb::AccessType default_accessibility,
|
||||
lldb_private::ClangASTImporter::LayoutInfo &layout_info,
|
||||
FieldInfo &last_field_info) {
|
||||
Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
|
||||
// This function can only parse DW_TAG_member.
|
||||
assert(die.Tag() == DW_TAG_member);
|
||||
|
||||
@ -2680,27 +2623,9 @@ void DWARFASTParserClang::ParseSingleMember(
|
||||
if (var_type) {
|
||||
if (attrs.accessibility == eAccessNone)
|
||||
attrs.accessibility = eAccessPublic;
|
||||
CompilerType ct = var_type->GetForwardCompilerType();
|
||||
clang::VarDecl *v = TypeSystemClang::AddVariableToRecordType(
|
||||
class_clang_type, attrs.name, ct, attrs.accessibility);
|
||||
if (!v) {
|
||||
LLDB_LOG(log, "Failed to add variable to the record type");
|
||||
return;
|
||||
}
|
||||
|
||||
bool unused;
|
||||
// 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) {
|
||||
LLDB_LOG_ERROR(log, const_value_or_err.takeError(),
|
||||
"Failed to add const value to variable {1}: {0}",
|
||||
v->getQualifiedNameAsString());
|
||||
return;
|
||||
}
|
||||
TypeSystemClang::SetIntegerInitializerForVariable(v, *const_value_or_err);
|
||||
TypeSystemClang::AddVariableToRecordType(
|
||||
class_clang_type, attrs.name, var_type->GetForwardCompilerType(),
|
||||
attrs.accessibility);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -68,22 +68,6 @@ public:
|
||||
|
||||
lldb_private::ClangASTImporter &GetClangASTImporter();
|
||||
|
||||
/// Extracts an value for a given Clang integer type from a DWARFFormValue.
|
||||
///
|
||||
/// \param int_type The Clang type that defines the bit size and signedness
|
||||
/// of the integer that should be extracted. Has to be either
|
||||
/// an integer type or an enum type. For enum types the
|
||||
/// underlying integer type will be considered as the
|
||||
/// expected integer type that should be extracted.
|
||||
/// \param form_value The DWARFFormValue that contains the integer value.
|
||||
/// \return An APInt containing the same integer value as the given
|
||||
/// DWARFFormValue with the bit width of the given integer type.
|
||||
/// Returns an error if the value in the DWARFFormValue does not fit
|
||||
/// into the given integer type or the integer type isn't supported.
|
||||
llvm::Expected<llvm::APInt>
|
||||
ExtractIntFromFormValue(const lldb_private::CompilerType &int_type,
|
||||
const DWARFFormValue &form_value) const;
|
||||
|
||||
protected:
|
||||
/// Protected typedefs and members.
|
||||
/// @{
|
||||
|
@ -1,3 +0,0 @@
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
include Makefile.rules
|
@ -1,94 +0,0 @@
|
||||
"""
|
||||
Tests const static data members as specified by C++11 [class.static.data]p3.
|
||||
"""
|
||||
|
||||
import lldb
|
||||
from lldbsuite.test.decorators import *
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test import lldbutil
|
||||
|
||||
class TestCase(TestBase):
|
||||
|
||||
mydir = TestBase.compute_mydir(__file__)
|
||||
|
||||
def test(self):
|
||||
self.build()
|
||||
lldbutil.run_to_source_breakpoint(self, "// break here",
|
||||
lldb.SBFileSpec("main.cpp"))
|
||||
|
||||
# Test using a simple const static integer member.
|
||||
self.expect_expr("A::int_val", result_value="1")
|
||||
|
||||
# Try accessing the int member via some expressions that still produce
|
||||
# an lvalue.
|
||||
self.expect_expr("a.int_val", result_value="1")
|
||||
self.expect_expr("(A::int_val)", result_value="1")
|
||||
self.expect_expr("+A::int_val", result_value="1")
|
||||
self.expect_expr("1,A::int_val", result_value="1")
|
||||
self.expect_expr("true ? A::int_val : A::int_val", result_value="1")
|
||||
|
||||
# Test a simple integer member that was also defined in a namespace
|
||||
# scope and has an address.
|
||||
self.expect_expr("A::int_val_with_address", result_value="2")
|
||||
|
||||
# Try to take the address of the data member. Should produce a linker
|
||||
# error only if the member doesn't have an address.
|
||||
self.expect("expr const int *i = &A::int_val; *i", error=True,
|
||||
substrs=["Couldn't lookup symbols:"])
|
||||
self.expect_expr("const int *i = &A::int_val_with_address; *i",
|
||||
result_value="2")
|
||||
|
||||
# Test a bool member.
|
||||
self.expect_expr("A::bool_val", result_value="true")
|
||||
|
||||
# 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")
|
||||
self.expect_expr("A::int_max == int_max", result_value="true")
|
||||
self.expect_expr("A::uint_max == uint_max", result_value="true")
|
||||
self.expect_expr("A::long_max == long_max", result_value="true")
|
||||
self.expect_expr("A::ulong_max == ulong_max", result_value="true")
|
||||
self.expect_expr("A::longlong_max == longlong_max", result_value="true")
|
||||
self.expect_expr("A::ulonglong_max == ulonglong_max", result_value="true")
|
||||
|
||||
self.expect_expr("A::char_min == char_min", result_value="true")
|
||||
self.expect_expr("A::uchar_min == uchar_min", result_value="true")
|
||||
self.expect_expr("A::int_min == int_min", result_value="true")
|
||||
self.expect_expr("A::uint_min == uint_min", result_value="true")
|
||||
self.expect_expr("A::long_min == long_min", result_value="true")
|
||||
self.expect_expr("A::ulong_min == ulong_min", result_value="true")
|
||||
self.expect_expr("A::longlong_min == longlong_min", result_value="true")
|
||||
self.expect_expr("A::ulonglong_min == ulonglong_min", result_value="true")
|
||||
|
||||
# Test an unscoped enum.
|
||||
self.expect_expr("A::enum_val", result_value="enum_case2")
|
||||
# Test an unscoped enum with an invalid enum case.
|
||||
self.expect_expr("A::invalid_enum_val", result_value="enum_case1 | enum_case2 | 0x4")
|
||||
|
||||
# Test a scoped enum.
|
||||
self.expect_expr("A::scoped_enum_val", result_value="scoped_enum_case2")
|
||||
# Test an scoped enum with an invalid enum case.
|
||||
self.expect_expr("A::invalid_scoped_enum_val", result_value="scoped_enum_case1 | 0x4")
|
||||
|
||||
# Test an enum with fixed underlying type.
|
||||
self.expect_expr("A::scoped_char_enum_val", result_value="case2")
|
||||
self.expect_expr("A::scoped_ll_enum_val_neg", result_value="case0")
|
||||
self.expect_expr("A::scoped_ll_enum_val", result_value="case2")
|
||||
|
||||
# Try to take the address of a member that doesn't have one.
|
||||
self.expect("expr const int *i = &A::int_val; *i", error=True,
|
||||
substrs=["Couldn't lookup symbols:"])
|
||||
|
||||
# dsymutil strips the debug info for classes that only have const static
|
||||
# data members without a definition namespace scope.
|
||||
@expectedFailureAll(debug_info=["dsym"])
|
||||
def test_class_with_only_const_static(self):
|
||||
self.build()
|
||||
lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.cpp"))
|
||||
|
||||
self.expect_expr("ClassWithOnlyConstStatic::member", result_value="3")
|
||||
|
||||
# Test `constexpr static`.
|
||||
self.expect_expr("ClassWithConstexprs::member", result_value="2")
|
||||
self.expect_expr("ClassWithConstexprs::enum_val", result_value="enum_case2")
|
||||
self.expect_expr("ClassWithConstexprs::scoped_enum_val", result_value="scoped_enum_case2")
|
@ -1,102 +0,0 @@
|
||||
#include <limits>
|
||||
|
||||
enum Enum {
|
||||
enum_case1 = 1,
|
||||
enum_case2 = 2,
|
||||
};
|
||||
|
||||
enum class ScopedEnum {
|
||||
scoped_enum_case1 = 1,
|
||||
scoped_enum_case2 = 2,
|
||||
};
|
||||
|
||||
enum class ScopedCharEnum : char {
|
||||
case1 = 1,
|
||||
case2 = 2,
|
||||
};
|
||||
|
||||
enum class ScopedLongLongEnum : long long {
|
||||
case0 = std::numeric_limits<long long>::min(),
|
||||
case1 = 1,
|
||||
case2 = std::numeric_limits<long long>::max(),
|
||||
};
|
||||
|
||||
struct A {
|
||||
const static int int_val = 1;
|
||||
const static int int_val_with_address = 2;
|
||||
const static bool bool_val = true;
|
||||
|
||||
const static auto char_max = std::numeric_limits<signed char>::max();
|
||||
const static auto uchar_max = std::numeric_limits<unsigned char>::max();
|
||||
const static auto int_max = std::numeric_limits<int>::max();
|
||||
const static auto uint_max = std::numeric_limits<unsigned>::max();
|
||||
const static auto long_max = std::numeric_limits<long>::max();
|
||||
const static auto ulong_max = std::numeric_limits<unsigned long>::max();
|
||||
const static auto longlong_max = std::numeric_limits<long long>::max();
|
||||
const static auto ulonglong_max =
|
||||
std::numeric_limits<unsigned long long>::max();
|
||||
|
||||
const static auto char_min = std::numeric_limits<char>::min();
|
||||
const static auto uchar_min = std::numeric_limits<unsigned char>::min();
|
||||
const static auto int_min = std::numeric_limits<int>::min();
|
||||
const static auto uint_min = std::numeric_limits<unsigned>::min();
|
||||
const static auto long_min = std::numeric_limits<long>::min();
|
||||
const static auto ulong_min = std::numeric_limits<unsigned long>::min();
|
||||
const static auto longlong_min = std::numeric_limits<long long>::min();
|
||||
const static auto ulonglong_min =
|
||||
std::numeric_limits<unsigned long long>::min();
|
||||
|
||||
const static Enum enum_val = enum_case2;
|
||||
const static Enum invalid_enum_val = static_cast<Enum>(enum_case2 + 5);
|
||||
const static ScopedEnum scoped_enum_val = ScopedEnum::scoped_enum_case2;
|
||||
const static ScopedEnum invalid_scoped_enum_val = static_cast<ScopedEnum>(5);
|
||||
const static ScopedCharEnum scoped_char_enum_val = ScopedCharEnum::case2;
|
||||
const static ScopedLongLongEnum scoped_ll_enum_val_neg =
|
||||
ScopedLongLongEnum::case0;
|
||||
const static ScopedLongLongEnum scoped_ll_enum_val =
|
||||
ScopedLongLongEnum::case2;
|
||||
};
|
||||
|
||||
const int A::int_val_with_address;
|
||||
|
||||
struct ClassWithOnlyConstStatic {
|
||||
const static int member = 3;
|
||||
};
|
||||
|
||||
struct ClassWithConstexprs {
|
||||
constexpr static int member = 2;
|
||||
constexpr static Enum enum_val = enum_case2;
|
||||
constexpr static ScopedEnum scoped_enum_val = ScopedEnum::scoped_enum_case2;
|
||||
} cwc;
|
||||
|
||||
int main() {
|
||||
A a;
|
||||
|
||||
auto char_max = A::char_max;
|
||||
auto uchar_max = A::uchar_max;
|
||||
auto int_max = A::int_max;
|
||||
auto uint_max = A::uint_max;
|
||||
auto long_max = A::long_max;
|
||||
auto ulong_max = A::ulong_max;
|
||||
auto longlong_max = A::longlong_max;
|
||||
auto ulonglong_max = A::ulonglong_max;
|
||||
|
||||
auto char_min = A::char_min;
|
||||
auto uchar_min = A::uchar_min;
|
||||
auto int_min = A::int_min;
|
||||
auto uint_min = A::uint_min;
|
||||
auto long_min = A::long_min;
|
||||
auto ulong_min = A::ulong_min;
|
||||
auto longlong_min = A::longlong_min;
|
||||
auto ulonglong_min = A::ulonglong_min;
|
||||
|
||||
int member_copy = ClassWithOnlyConstStatic::member;
|
||||
|
||||
Enum e = A::enum_val;
|
||||
e = A::invalid_enum_val;
|
||||
ScopedEnum se = A::scoped_enum_val;
|
||||
se = A::invalid_scoped_enum_val;
|
||||
ScopedCharEnum sce = A::scoped_char_enum_val;
|
||||
ScopedLongLongEnum sle = A::scoped_ll_enum_val;
|
||||
return 0; // break here
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
include Makefile.rules
|
@ -1,31 +0,0 @@
|
||||
"""
|
||||
Tests const static data members as specified by C++11 [class.static.data]p3
|
||||
with (u)int128_t types.
|
||||
"""
|
||||
|
||||
import lldb
|
||||
from lldbsuite.test.decorators import *
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test import lldbutil
|
||||
|
||||
class TestCase(TestBase):
|
||||
|
||||
mydir = TestBase.compute_mydir(__file__)
|
||||
|
||||
def test_int128(self):
|
||||
self.build()
|
||||
lldbutil.run_to_source_breakpoint(self, "// break here",
|
||||
lldb.SBFileSpec("main.cpp"))
|
||||
|
||||
# Try to use the (u)int128_t data members which are not supported at
|
||||
# the moment. Just verify that LLDB doesn't report an incorrect value
|
||||
# for them and just treats them as normal variables (which will lead
|
||||
# to linker errors as they are not defined anywhere).
|
||||
self.expect("expr A::int128_max", error=True,
|
||||
substrs=["Couldn't lookup symbols:"])
|
||||
self.expect("expr A::uint128_max", error=True,
|
||||
substrs=["Couldn't lookup symbols:"])
|
||||
self.expect("expr A::int128_min", error=True,
|
||||
substrs=["Couldn't lookup symbols:"])
|
||||
self.expect("expr A::uint128_min", error=True,
|
||||
substrs=["Couldn't lookup symbols:"])
|
@ -1,18 +0,0 @@
|
||||
#include <limits>
|
||||
|
||||
struct A {
|
||||
const static auto uint128_max = std::numeric_limits<__uint128_t>::max();
|
||||
const static auto uint128_min = std::numeric_limits<__uint128_t>::min();
|
||||
const static auto int128_max = std::numeric_limits<__int128_t>::max();
|
||||
const static auto int128_min = std::numeric_limits<__int128_t>::min();
|
||||
};
|
||||
|
||||
int main() {
|
||||
A a;
|
||||
|
||||
auto int128_max = A::int128_max;
|
||||
auto uint128_max = A::uint128_max;
|
||||
auto int128_min = A::int128_min;
|
||||
auto uint128_min = A::uint128_min;
|
||||
return 0; // break here
|
||||
}
|
@ -17,7 +17,6 @@ add_lldb_unittest(SymbolFileDWARFTests
|
||||
lldbPluginPlatformMacOSX
|
||||
lldbUtilityHelpers
|
||||
lldbSymbolHelpers
|
||||
LLVMTestingSupport
|
||||
LINK_COMPONENTS
|
||||
Support
|
||||
DebugInfoPDB
|
||||
|
@ -273,128 +273,3 @@ DWARF:
|
||||
};
|
||||
ASSERT_EQ(found_function_types, expected_function_types);
|
||||
}
|
||||
|
||||
struct ExtractIntFromFormValueTest : public testing::Test {
|
||||
SubsystemRAII<FileSystem, HostInfo> subsystems;
|
||||
TypeSystemClang ts;
|
||||
DWARFASTParserClang parser;
|
||||
ExtractIntFromFormValueTest()
|
||||
: ts("dummy ASTContext", HostInfoBase::GetTargetTriple()), parser(ts) {}
|
||||
|
||||
/// Takes the given integer value, stores it in a DWARFFormValue and then
|
||||
/// tries to extract the value back via
|
||||
/// DWARFASTParserClang::ExtractIntFromFormValue.
|
||||
/// Returns the string representation of the extracted value or the error
|
||||
/// that was returned from ExtractIntFromFormValue.
|
||||
llvm::Expected<std::string> Extract(clang::QualType qt, uint64_t value) {
|
||||
DWARFFormValue form_value;
|
||||
form_value.SetUnsigned(value);
|
||||
llvm::Expected<llvm::APInt> result =
|
||||
parser.ExtractIntFromFormValue(ts.GetType(qt), form_value);
|
||||
if (!result)
|
||||
return result.takeError();
|
||||
llvm::SmallString<16> result_str;
|
||||
result->toStringUnsigned(result_str);
|
||||
return std::string(result_str.str());
|
||||
}
|
||||
|
||||
/// Same as ExtractIntFromFormValueTest::Extract but takes a signed integer
|
||||
/// and treats the result as a signed integer.
|
||||
llvm::Expected<std::string> ExtractS(clang::QualType qt, int64_t value) {
|
||||
DWARFFormValue form_value;
|
||||
form_value.SetSigned(value);
|
||||
llvm::Expected<llvm::APInt> result =
|
||||
parser.ExtractIntFromFormValue(ts.GetType(qt), form_value);
|
||||
if (!result)
|
||||
return result.takeError();
|
||||
llvm::SmallString<16> result_str;
|
||||
result->toStringSigned(result_str);
|
||||
return std::string(result_str.str());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ExtractIntFromFormValueTest, TestBool) {
|
||||
using namespace llvm;
|
||||
clang::ASTContext &ast = ts.getASTContext();
|
||||
|
||||
EXPECT_THAT_EXPECTED(Extract(ast.BoolTy, 0), HasValue("0"));
|
||||
EXPECT_THAT_EXPECTED(Extract(ast.BoolTy, 1), HasValue("1"));
|
||||
EXPECT_THAT_EXPECTED(Extract(ast.BoolTy, 2), Failed());
|
||||
EXPECT_THAT_EXPECTED(Extract(ast.BoolTy, 3), Failed());
|
||||
}
|
||||
|
||||
TEST_F(ExtractIntFromFormValueTest, TestInt) {
|
||||
using namespace llvm;
|
||||
|
||||
clang::ASTContext &ast = ts.getASTContext();
|
||||
|
||||
// Find the min/max values for 'int' on the current host target.
|
||||
constexpr int64_t int_max = std::numeric_limits<int>::max();
|
||||
constexpr int64_t int_min = std::numeric_limits<int>::min();
|
||||
|
||||
// Check that the bit width of int matches the int width in our type system.
|
||||
ASSERT_EQ(sizeof(int) * 8, ast.getIntWidth(ast.IntTy));
|
||||
|
||||
// Check values around int_min.
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min - 2), llvm::Failed());
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min - 1), llvm::Failed());
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min),
|
||||
HasValue(std::to_string(int_min)));
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min + 1),
|
||||
HasValue(std::to_string(int_min + 1)));
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min + 2),
|
||||
HasValue(std::to_string(int_min + 2)));
|
||||
|
||||
// Check values around 0.
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, -128), HasValue("-128"));
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, -10), HasValue("-10"));
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, -1), HasValue("-1"));
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, 0), HasValue("0"));
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, 1), HasValue("1"));
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, 10), HasValue("10"));
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, 128), HasValue("128"));
|
||||
|
||||
// Check values around int_max.
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max - 2),
|
||||
HasValue(std::to_string(int_max - 2)));
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max - 1),
|
||||
HasValue(std::to_string(int_max - 1)));
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max),
|
||||
HasValue(std::to_string(int_max)));
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max + 1), llvm::Failed());
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max + 5), llvm::Failed());
|
||||
|
||||
// Check some values not near an edge case.
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max / 2),
|
||||
HasValue(std::to_string(int_max / 2)));
|
||||
EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min / 2),
|
||||
HasValue(std::to_string(int_min / 2)));
|
||||
}
|
||||
|
||||
TEST_F(ExtractIntFromFormValueTest, TestUnsignedInt) {
|
||||
using namespace llvm;
|
||||
|
||||
clang::ASTContext &ast = ts.getASTContext();
|
||||
constexpr uint64_t uint_max = std::numeric_limits<uint32_t>::max();
|
||||
|
||||
// Check values around 0.
|
||||
EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, 0), HasValue("0"));
|
||||
EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, 1), HasValue("1"));
|
||||
EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, 1234), HasValue("1234"));
|
||||
|
||||
// Check some values not near an edge case.
|
||||
EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max / 2),
|
||||
HasValue(std::to_string(uint_max / 2)));
|
||||
|
||||
// Check values around uint_max.
|
||||
EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max - 2),
|
||||
HasValue(std::to_string(uint_max - 2)));
|
||||
EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max - 1),
|
||||
HasValue(std::to_string(uint_max - 1)));
|
||||
EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max),
|
||||
HasValue(std::to_string(uint_max)));
|
||||
EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max + 1),
|
||||
llvm::Failed());
|
||||
EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max + 2),
|
||||
llvm::Failed());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user