mirror of
https://github.com/intel/llvm.git
synced 2026-01-12 18:27:07 +08:00
[LLDB] Add unary plus and minus to DIL (#155617)
This patch adds unary nodes plus and minus, introduces unary type conversions, and adds integral promotion to the type system.
This commit is contained in:
@@ -8,7 +8,7 @@ expression = unary_expression ;
|
||||
unary_expression = postfix_expression
|
||||
| unary_operator expression ;
|
||||
|
||||
unary_operator = "*" | "&" ;
|
||||
unary_operator = "*" | "&" | "+" | "-";
|
||||
|
||||
postfix_expression = primary_expression
|
||||
| postfix_expression "[" integer_literal "]"
|
||||
|
||||
@@ -411,6 +411,18 @@ public:
|
||||
GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type, size_t idx,
|
||||
bool expand_pack);
|
||||
|
||||
// DIL
|
||||
|
||||
/// Checks if the type is eligible for integral promotion.
|
||||
virtual bool IsPromotableIntegerType(lldb::opaque_compiler_type_t type);
|
||||
|
||||
/// Perform integral promotion on a given type.
|
||||
/// This promotes eligible types (boolean, integers, unscoped enumerations)
|
||||
/// to a larger integer type according to type system rules.
|
||||
/// \returns Promoted type.
|
||||
virtual llvm::Expected<CompilerType>
|
||||
DoIntegralPromotion(CompilerType from, ExecutionContextScope *exe_scope);
|
||||
|
||||
// Dumping types
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
@@ -33,6 +33,8 @@ enum class NodeKind {
|
||||
enum class UnaryOpKind {
|
||||
AddrOf, // "&"
|
||||
Deref, // "*"
|
||||
Minus, // "-"
|
||||
Plus, // "+"
|
||||
};
|
||||
|
||||
/// Forward declaration, for use in DIL AST nodes. Definition is at the very
|
||||
|
||||
@@ -61,6 +61,10 @@ private:
|
||||
llvm::Expected<lldb::ValueObjectSP>
|
||||
Visit(const BooleanLiteralNode *node) override;
|
||||
|
||||
/// Perform usual unary conversions on a value. At the moment this
|
||||
/// includes array-to-pointer and integral promotion for eligible types.
|
||||
llvm::Expected<lldb::ValueObjectSP>
|
||||
UnaryConversion(lldb::ValueObjectSP valobj, uint32_t location);
|
||||
llvm::Expected<CompilerType>
|
||||
PickIntegerType(lldb::TypeSystemSP type_system,
|
||||
std::shared_ptr<ExecutionContextScope> ctx,
|
||||
|
||||
@@ -7346,6 +7346,102 @@ CompilerType TypeSystemClang::GetTypeForFormatters(void *type) {
|
||||
return CompilerType();
|
||||
}
|
||||
|
||||
bool TypeSystemClang::IsPromotableIntegerType(
|
||||
lldb::opaque_compiler_type_t type) {
|
||||
// Unscoped enums are always considered as promotable, even if their
|
||||
// underlying type does not need to be promoted (e.g. "int").
|
||||
bool is_signed = false;
|
||||
bool isUnscopedEnumerationType =
|
||||
IsEnumerationType(type, is_signed) && !IsScopedEnumerationType(type);
|
||||
if (isUnscopedEnumerationType)
|
||||
return true;
|
||||
|
||||
switch (GetBasicTypeEnumeration(type)) {
|
||||
case lldb::eBasicTypeBool:
|
||||
case lldb::eBasicTypeChar:
|
||||
case lldb::eBasicTypeSignedChar:
|
||||
case lldb::eBasicTypeUnsignedChar:
|
||||
case lldb::eBasicTypeShort:
|
||||
case lldb::eBasicTypeUnsignedShort:
|
||||
case lldb::eBasicTypeWChar:
|
||||
case lldb::eBasicTypeSignedWChar:
|
||||
case lldb::eBasicTypeUnsignedWChar:
|
||||
case lldb::eBasicTypeChar16:
|
||||
case lldb::eBasicTypeChar32:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm_unreachable("All cases handled above.");
|
||||
}
|
||||
|
||||
llvm::Expected<CompilerType>
|
||||
TypeSystemClang::DoIntegralPromotion(CompilerType from,
|
||||
ExecutionContextScope *exe_scope) {
|
||||
if (!from.IsInteger() && !from.IsUnscopedEnumerationType())
|
||||
return from;
|
||||
|
||||
if (!from.IsPromotableIntegerType())
|
||||
return from;
|
||||
|
||||
if (from.IsUnscopedEnumerationType()) {
|
||||
EnumDecl *enum_decl = GetAsEnumDecl(from);
|
||||
CompilerType promotion_type = GetType(enum_decl->getPromotionType());
|
||||
return DoIntegralPromotion(promotion_type, exe_scope);
|
||||
}
|
||||
|
||||
lldb::BasicType builtin_type =
|
||||
from.GetCanonicalType().GetBasicTypeEnumeration();
|
||||
uint64_t from_size = 0;
|
||||
if (builtin_type == lldb::eBasicTypeWChar ||
|
||||
builtin_type == lldb::eBasicTypeSignedWChar ||
|
||||
builtin_type == lldb::eBasicTypeUnsignedWChar ||
|
||||
builtin_type == lldb::eBasicTypeChar16 ||
|
||||
builtin_type == lldb::eBasicTypeChar32) {
|
||||
// Find the type that can hold the entire range of values for our type.
|
||||
bool is_signed = from.IsSigned();
|
||||
llvm::Expected<uint64_t> from_size = from.GetByteSize(exe_scope);
|
||||
if (!from_size)
|
||||
return from_size.takeError();
|
||||
CompilerType promote_types[] = {
|
||||
GetBasicTypeFromAST(lldb::eBasicTypeInt),
|
||||
GetBasicTypeFromAST(lldb::eBasicTypeUnsignedInt),
|
||||
GetBasicTypeFromAST(lldb::eBasicTypeLong),
|
||||
GetBasicTypeFromAST(lldb::eBasicTypeUnsignedLong),
|
||||
GetBasicTypeFromAST(lldb::eBasicTypeLongLong),
|
||||
GetBasicTypeFromAST(lldb::eBasicTypeUnsignedLongLong),
|
||||
};
|
||||
for (CompilerType &type : promote_types) {
|
||||
llvm::Expected<uint64_t> byte_size = type.GetByteSize(exe_scope);
|
||||
if (!byte_size)
|
||||
return byte_size.takeError();
|
||||
if (*from_size < *byte_size ||
|
||||
(*from_size == *byte_size && is_signed == type.IsSigned())) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
llvm_unreachable("char type should fit into long long");
|
||||
}
|
||||
|
||||
// Here we can promote only to "int" or "unsigned int".
|
||||
CompilerType int_type = GetBasicTypeFromAST(lldb::eBasicTypeInt);
|
||||
llvm::Expected<uint64_t> int_byte_size = int_type.GetByteSize(exe_scope);
|
||||
if (!int_byte_size)
|
||||
return int_byte_size.takeError();
|
||||
|
||||
// Signed integer types can be safely promoted to "int".
|
||||
if (from.IsSigned()) {
|
||||
return int_type;
|
||||
}
|
||||
// Unsigned integer types are promoted to "unsigned int" if "int" cannot hold
|
||||
// their entire value range.
|
||||
return (from_size == *int_byte_size)
|
||||
? GetBasicTypeFromAST(lldb::eBasicTypeUnsignedInt)
|
||||
: int_type;
|
||||
}
|
||||
|
||||
clang::EnumDecl *TypeSystemClang::GetAsEnumDecl(const CompilerType &type) {
|
||||
const clang::EnumType *enutype =
|
||||
llvm::dyn_cast<clang::EnumType>(ClangUtil::GetCanonicalQualType(type));
|
||||
|
||||
@@ -938,6 +938,14 @@ public:
|
||||
|
||||
CompilerType GetTypeForFormatters(void *type) override;
|
||||
|
||||
// DIL
|
||||
|
||||
bool IsPromotableIntegerType(lldb::opaque_compiler_type_t type) override;
|
||||
|
||||
llvm::Expected<CompilerType>
|
||||
DoIntegralPromotion(CompilerType from,
|
||||
ExecutionContextScope *exe_scope) override;
|
||||
|
||||
#define LLDB_INVALID_DECL_LEVEL UINT32_MAX
|
||||
// LLDB_INVALID_DECL_LEVEL is returned by CountDeclLevels if child_decl_ctx
|
||||
// could not be found in decl_ctx.
|
||||
|
||||
@@ -370,30 +370,10 @@ bool CompilerType::IsScalarOrUnscopedEnumerationType() const {
|
||||
}
|
||||
|
||||
bool CompilerType::IsPromotableIntegerType() const {
|
||||
// Unscoped enums are always considered as promotable, even if their
|
||||
// underlying type does not need to be promoted (e.g. "int").
|
||||
if (IsUnscopedEnumerationType())
|
||||
return true;
|
||||
|
||||
switch (GetBasicTypeEnumeration()) {
|
||||
case lldb::eBasicTypeBool:
|
||||
case lldb::eBasicTypeChar:
|
||||
case lldb::eBasicTypeSignedChar:
|
||||
case lldb::eBasicTypeUnsignedChar:
|
||||
case lldb::eBasicTypeShort:
|
||||
case lldb::eBasicTypeUnsignedShort:
|
||||
case lldb::eBasicTypeWChar:
|
||||
case lldb::eBasicTypeSignedWChar:
|
||||
case lldb::eBasicTypeUnsignedWChar:
|
||||
case lldb::eBasicTypeChar16:
|
||||
case lldb::eBasicTypeChar32:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm_unreachable("All cases handled above.");
|
||||
if (IsValid())
|
||||
if (auto type_system_sp = GetTypeSystem())
|
||||
return type_system_sp->IsPromotableIntegerType(m_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CompilerType::IsPointerToVoid() const {
|
||||
|
||||
@@ -123,6 +123,17 @@ CompilerType TypeSystem::GetTypeForFormatters(void *type) {
|
||||
return CompilerType(weak_from_this(), type);
|
||||
}
|
||||
|
||||
bool TypeSystem::IsPromotableIntegerType(lldb::opaque_compiler_type_t type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm::Expected<CompilerType>
|
||||
TypeSystem::DoIntegralPromotion(CompilerType from,
|
||||
ExecutionContextScope *exe_scope) {
|
||||
return llvm::createStringError(
|
||||
"Integral promotion is not implemented for this TypeSystem");
|
||||
}
|
||||
|
||||
bool TypeSystem::IsTemplateType(lldb::opaque_compiler_type_t type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,101 @@
|
||||
|
||||
namespace lldb_private::dil {
|
||||
|
||||
static llvm::Expected<lldb::TypeSystemSP>
|
||||
GetTypeSystemFromCU(std::shared_ptr<ExecutionContextScope> ctx) {
|
||||
auto stack_frame = ctx->CalculateStackFrame();
|
||||
if (!stack_frame)
|
||||
return llvm::createStringError("no stack frame in this context");
|
||||
SymbolContext symbol_context =
|
||||
stack_frame->GetSymbolContext(lldb::eSymbolContextCompUnit);
|
||||
lldb::LanguageType language = symbol_context.comp_unit->GetLanguage();
|
||||
|
||||
symbol_context = stack_frame->GetSymbolContext(lldb::eSymbolContextModule);
|
||||
return symbol_context.module_sp->GetTypeSystemForLanguage(language);
|
||||
}
|
||||
|
||||
static CompilerType GetBasicType(lldb::TypeSystemSP type_system,
|
||||
lldb::BasicType basic_type) {
|
||||
if (type_system)
|
||||
return type_system.get()->GetBasicTypeFromAST(basic_type);
|
||||
|
||||
return CompilerType();
|
||||
}
|
||||
|
||||
static lldb::ValueObjectSP
|
||||
ArrayToPointerConversion(ValueObject &valobj, ExecutionContextScope &ctx) {
|
||||
uint64_t addr = valobj.GetLoadAddress();
|
||||
ExecutionContext exe_ctx;
|
||||
ctx.CalculateExecutionContext(exe_ctx);
|
||||
return ValueObject::CreateValueObjectFromAddress(
|
||||
"result", addr, exe_ctx,
|
||||
valobj.GetCompilerType().GetArrayElementType(&ctx).GetPointerType(),
|
||||
/* do_deref */ false);
|
||||
}
|
||||
|
||||
llvm::Expected<lldb::ValueObjectSP>
|
||||
Interpreter::UnaryConversion(lldb::ValueObjectSP valobj, uint32_t location) {
|
||||
if (!valobj)
|
||||
return llvm::make_error<DILDiagnosticError>(m_expr, "invalid value object",
|
||||
location);
|
||||
llvm::Expected<lldb::TypeSystemSP> type_system =
|
||||
GetTypeSystemFromCU(m_exe_ctx_scope);
|
||||
if (!type_system)
|
||||
return type_system.takeError();
|
||||
|
||||
CompilerType in_type = valobj->GetCompilerType();
|
||||
if (valobj->IsBitfield()) {
|
||||
// Promote bitfields. If `int` can represent the bitfield value, it is
|
||||
// converted to `int`. Otherwise, if `unsigned int` can represent it, it
|
||||
// is converted to `unsigned int`. Otherwise, it is treated as its
|
||||
// underlying type.
|
||||
uint32_t bitfield_size = valobj->GetBitfieldBitSize();
|
||||
// Some bitfields have undefined size (e.g. result of ternary operation).
|
||||
// The AST's `bitfield_size` of those is 0, and no promotion takes place.
|
||||
if (bitfield_size > 0 && in_type.IsInteger()) {
|
||||
CompilerType int_type = GetBasicType(*type_system, lldb::eBasicTypeInt);
|
||||
CompilerType uint_type =
|
||||
GetBasicType(*type_system, lldb::eBasicTypeUnsignedInt);
|
||||
llvm::Expected<uint64_t> int_bit_size =
|
||||
int_type.GetBitSize(m_exe_ctx_scope.get());
|
||||
if (!int_bit_size)
|
||||
return int_bit_size.takeError();
|
||||
llvm::Expected<uint64_t> uint_bit_size =
|
||||
uint_type.GetBitSize(m_exe_ctx_scope.get());
|
||||
if (!uint_bit_size)
|
||||
return int_bit_size.takeError();
|
||||
if (bitfield_size < *int_bit_size ||
|
||||
(in_type.IsSigned() && bitfield_size == *int_bit_size))
|
||||
return valobj->CastToBasicType(int_type);
|
||||
if (bitfield_size <= *uint_bit_size)
|
||||
return valobj->CastToBasicType(uint_type);
|
||||
// Re-create as a const value with the same underlying type
|
||||
Scalar scalar;
|
||||
bool resolved = valobj->ResolveValue(scalar);
|
||||
if (!resolved)
|
||||
return llvm::createStringError("invalid scalar value");
|
||||
return ValueObject::CreateValueObjectFromScalar(m_target, scalar, in_type,
|
||||
"result");
|
||||
}
|
||||
}
|
||||
|
||||
if (in_type.IsArrayType())
|
||||
valobj = ArrayToPointerConversion(*valobj, *m_exe_ctx_scope);
|
||||
|
||||
if (valobj->GetCompilerType().IsInteger() ||
|
||||
valobj->GetCompilerType().IsUnscopedEnumerationType()) {
|
||||
llvm::Expected<CompilerType> promoted_type =
|
||||
type_system.get()->DoIntegralPromotion(valobj->GetCompilerType(),
|
||||
m_exe_ctx_scope.get());
|
||||
if (!promoted_type)
|
||||
return promoted_type.takeError();
|
||||
if (!promoted_type->CompareTypes(valobj->GetCompilerType()))
|
||||
return valobj->CastToBasicType(*promoted_type);
|
||||
}
|
||||
|
||||
return valobj;
|
||||
}
|
||||
|
||||
static lldb::VariableSP DILFindVariable(ConstString name,
|
||||
VariableList &variable_list) {
|
||||
lldb::VariableSP exact_match;
|
||||
@@ -147,6 +242,10 @@ Interpreter::Interpreter(lldb::TargetSP target, llvm::StringRef expr,
|
||||
llvm::Expected<lldb::ValueObjectSP> Interpreter::Evaluate(const ASTNode *node) {
|
||||
// Evaluate an AST.
|
||||
auto value_or_error = node->Accept(this);
|
||||
// Convert SP with a nullptr to an error.
|
||||
if (value_or_error && !*value_or_error)
|
||||
return llvm::make_error<DILDiagnosticError>(m_expr, "invalid value object",
|
||||
node->GetLocation());
|
||||
// Return the computed value-or-error. The caller is responsible for
|
||||
// checking if an error occured during the evaluation.
|
||||
return value_or_error;
|
||||
@@ -175,21 +274,21 @@ Interpreter::Visit(const IdentifierNode *node) {
|
||||
llvm::Expected<lldb::ValueObjectSP>
|
||||
Interpreter::Visit(const UnaryOpNode *node) {
|
||||
Status error;
|
||||
auto rhs_or_err = Evaluate(node->GetOperand());
|
||||
if (!rhs_or_err)
|
||||
return rhs_or_err;
|
||||
auto op_or_err = Evaluate(node->GetOperand());
|
||||
if (!op_or_err)
|
||||
return op_or_err;
|
||||
|
||||
lldb::ValueObjectSP rhs = *rhs_or_err;
|
||||
lldb::ValueObjectSP operand = *op_or_err;
|
||||
|
||||
switch (node->GetKind()) {
|
||||
case UnaryOpKind::Deref: {
|
||||
lldb::ValueObjectSP dynamic_rhs = rhs->GetDynamicValue(m_use_dynamic);
|
||||
if (dynamic_rhs)
|
||||
rhs = dynamic_rhs;
|
||||
lldb::ValueObjectSP dynamic_op = operand->GetDynamicValue(m_use_dynamic);
|
||||
if (dynamic_op)
|
||||
operand = dynamic_op;
|
||||
|
||||
lldb::ValueObjectSP child_sp = rhs->Dereference(error);
|
||||
lldb::ValueObjectSP child_sp = operand->Dereference(error);
|
||||
if (!child_sp && m_use_synthetic) {
|
||||
if (lldb::ValueObjectSP synth_obj_sp = rhs->GetSyntheticValue()) {
|
||||
if (lldb::ValueObjectSP synth_obj_sp = operand->GetSyntheticValue()) {
|
||||
error.Clear();
|
||||
child_sp = synth_obj_sp->Dereference(error);
|
||||
}
|
||||
@@ -202,18 +301,69 @@ Interpreter::Visit(const UnaryOpNode *node) {
|
||||
}
|
||||
case UnaryOpKind::AddrOf: {
|
||||
Status error;
|
||||
lldb::ValueObjectSP value = rhs->AddressOf(error);
|
||||
lldb::ValueObjectSP value = operand->AddressOf(error);
|
||||
if (error.Fail())
|
||||
return llvm::make_error<DILDiagnosticError>(m_expr, error.AsCString(),
|
||||
node->GetLocation());
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
case UnaryOpKind::Minus: {
|
||||
if (operand->GetCompilerType().IsReferenceType()) {
|
||||
operand = operand->Dereference(error);
|
||||
if (error.Fail())
|
||||
return error.ToError();
|
||||
}
|
||||
llvm::Expected<lldb::ValueObjectSP> conv_op =
|
||||
UnaryConversion(operand, node->GetOperand()->GetLocation());
|
||||
if (!conv_op)
|
||||
return conv_op;
|
||||
operand = *conv_op;
|
||||
CompilerType operand_type = operand->GetCompilerType();
|
||||
if (!operand_type.IsScalarType()) {
|
||||
std::string errMsg =
|
||||
llvm::formatv("invalid argument type '{0}' to unary expression",
|
||||
operand_type.GetTypeName());
|
||||
return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
|
||||
node->GetLocation());
|
||||
}
|
||||
Scalar scalar;
|
||||
bool resolved = operand->ResolveValue(scalar);
|
||||
if (!resolved)
|
||||
break;
|
||||
|
||||
// Unsupported/invalid operation.
|
||||
return llvm::make_error<DILDiagnosticError>(
|
||||
m_expr, "invalid ast: unexpected binary operator", node->GetLocation());
|
||||
bool negated = scalar.UnaryNegate();
|
||||
if (negated)
|
||||
return ValueObject::CreateValueObjectFromScalar(
|
||||
m_target, scalar, operand->GetCompilerType(), "result");
|
||||
break;
|
||||
}
|
||||
case UnaryOpKind::Plus: {
|
||||
if (operand->GetCompilerType().IsReferenceType()) {
|
||||
operand = operand->Dereference(error);
|
||||
if (error.Fail())
|
||||
return error.ToError();
|
||||
}
|
||||
llvm::Expected<lldb::ValueObjectSP> conv_op =
|
||||
UnaryConversion(operand, node->GetOperand()->GetLocation());
|
||||
if (!conv_op)
|
||||
return conv_op;
|
||||
operand = *conv_op;
|
||||
CompilerType operand_type = operand->GetCompilerType();
|
||||
if (!operand_type.IsScalarType() &&
|
||||
// Unary plus is allowed for pointers.
|
||||
!operand_type.IsPointerType()) {
|
||||
std::string errMsg =
|
||||
llvm::formatv("invalid argument type '{0}' to unary expression",
|
||||
operand_type.GetTypeName());
|
||||
return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
|
||||
node->GetLocation());
|
||||
}
|
||||
return operand;
|
||||
}
|
||||
}
|
||||
return llvm::make_error<DILDiagnosticError>(m_expr, "invalid unary operation",
|
||||
node->GetLocation());
|
||||
}
|
||||
|
||||
llvm::Expected<lldb::ValueObjectSP>
|
||||
@@ -499,24 +649,6 @@ Interpreter::Visit(const BitFieldExtractionNode *node) {
|
||||
return child_valobj_sp;
|
||||
}
|
||||
|
||||
static llvm::Expected<lldb::TypeSystemSP>
|
||||
GetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx) {
|
||||
SymbolContext symbol_context =
|
||||
ctx->GetSymbolContext(lldb::eSymbolContextCompUnit);
|
||||
lldb::LanguageType language = symbol_context.comp_unit->GetLanguage();
|
||||
|
||||
symbol_context = ctx->GetSymbolContext(lldb::eSymbolContextModule);
|
||||
return symbol_context.module_sp->GetTypeSystemForLanguage(language);
|
||||
}
|
||||
|
||||
static CompilerType GetBasicType(lldb::TypeSystemSP type_system,
|
||||
lldb::BasicType basic_type) {
|
||||
if (type_system)
|
||||
return type_system.get()->GetBasicTypeFromAST(basic_type);
|
||||
|
||||
return CompilerType();
|
||||
}
|
||||
|
||||
llvm::Expected<CompilerType>
|
||||
Interpreter::PickIntegerType(lldb::TypeSystemSP type_system,
|
||||
std::shared_ptr<ExecutionContextScope> ctx,
|
||||
|
||||
@@ -93,9 +93,12 @@ ASTNodeUP DILParser::ParseExpression() { return ParseUnaryExpression(); }
|
||||
// unary_operator:
|
||||
// "&"
|
||||
// "*"
|
||||
// "+"
|
||||
// "-"
|
||||
//
|
||||
ASTNodeUP DILParser::ParseUnaryExpression() {
|
||||
if (CurToken().IsOneOf({Token::amp, Token::star})) {
|
||||
if (CurToken().IsOneOf(
|
||||
{Token::amp, Token::star, Token::minus, Token::plus})) {
|
||||
Token token = CurToken();
|
||||
uint32_t loc = token.GetLocation();
|
||||
m_dil_lexer.Advance();
|
||||
@@ -107,7 +110,12 @@ ASTNodeUP DILParser::ParseUnaryExpression() {
|
||||
case Token::amp:
|
||||
return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::AddrOf,
|
||||
std::move(rhs));
|
||||
|
||||
case Token::minus:
|
||||
return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::Minus,
|
||||
std::move(rhs));
|
||||
case Token::plus:
|
||||
return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::Plus,
|
||||
std::move(rhs));
|
||||
default:
|
||||
llvm_unreachable("invalid token kind");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
include Makefile.rules
|
||||
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
Test DIL arithmetic.
|
||||
"""
|
||||
|
||||
import lldb
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test.decorators import *
|
||||
from lldbsuite.test import lldbutil
|
||||
|
||||
|
||||
class TestFrameVarDILArithmetic(TestBase):
|
||||
NO_DEBUG_INFO_TESTCASE = True
|
||||
|
||||
def test_arithmetic(self):
|
||||
self.build()
|
||||
lldbutil.run_to_source_breakpoint(
|
||||
self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
|
||||
)
|
||||
|
||||
self.runCmd("settings set target.experimental.use-DIL true")
|
||||
|
||||
# Check unary results and integral promotion
|
||||
self.expect_var_path("+0", value="0")
|
||||
self.expect_var_path("-0", value="0")
|
||||
self.expect_var_path("+1", value="1")
|
||||
self.expect_var_path("-1", value="-1")
|
||||
self.expect_var_path("-9223372036854775808", value="9223372036854775808")
|
||||
self.expect_var_path("s", value="10", type="short")
|
||||
self.expect_var_path("+s", value="10", type="int")
|
||||
self.expect_var_path("-s", value="-10", type="int")
|
||||
self.expect_var_path("+us", value="1", type="int")
|
||||
self.expect_var_path("-us", value="-1", type="int")
|
||||
self.expect_var_path("+ref", value="2", type="int")
|
||||
self.expect_var_path("-ref", value="-2", type="int")
|
||||
self.expect_var_path("+0.0", value="0")
|
||||
self.expect_var_path("-0.0", value="-0")
|
||||
self.expect_var_path("+enum_one", value="1")
|
||||
self.expect_var_path("-enum_one", value="-1")
|
||||
self.expect_var_path("+wchar", value="1")
|
||||
self.expect_var_path("+char16", value="2")
|
||||
self.expect_var_path("+char32", value="3")
|
||||
self.expect_var_path("-bitfield.a", value="-1", type="int")
|
||||
self.expect_var_path("+bitfield.a", value="1", type="int")
|
||||
self.expect_var_path("+bitfield.b", value="2", type="int")
|
||||
self.expect_var_path("+bitfield.c", value="3", type="unsigned int")
|
||||
self.expect_var_path("+bitfield.d", value="4", type="uint64_t")
|
||||
@@ -0,0 +1,23 @@
|
||||
#include <cstdint>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
short s = 10;
|
||||
unsigned short us = 1;
|
||||
|
||||
int x = 2;
|
||||
int &ref = x;
|
||||
enum Enum { kZero, kOne } enum_one = kOne;
|
||||
wchar_t wchar = 1;
|
||||
char16_t char16 = 2;
|
||||
char32_t char32 = 3;
|
||||
|
||||
struct BitFieldStruct {
|
||||
char a : 4;
|
||||
int b : 32;
|
||||
unsigned int c : 32;
|
||||
uint64_t d : 48;
|
||||
};
|
||||
BitFieldStruct bitfield = {1, 2, 3, 4};
|
||||
|
||||
return 0; // Set a breakpoint here
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
include Makefile.rules
|
||||
@@ -0,0 +1,29 @@
|
||||
"""
|
||||
Test DIL pointer arithmetic.
|
||||
"""
|
||||
|
||||
import lldb
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test.decorators import *
|
||||
from lldbsuite.test import lldbutil
|
||||
|
||||
|
||||
class TestFrameVarDILPointerArithmetic(TestBase):
|
||||
NO_DEBUG_INFO_TESTCASE = True
|
||||
|
||||
def test_pointer_arithmetic(self):
|
||||
self.build()
|
||||
lldbutil.run_to_source_breakpoint(
|
||||
self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
|
||||
)
|
||||
|
||||
self.runCmd("settings set target.experimental.use-DIL true")
|
||||
|
||||
self.expect_var_path("+array", type="int *")
|
||||
self.expect_var_path("+array_ref", type="int *")
|
||||
self.expect_var_path("+p_int0", type="int *")
|
||||
self.expect(
|
||||
"frame var -- '-p_int0'",
|
||||
error=True,
|
||||
substrs=["invalid argument type 'int *' to unary expression"],
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
void stop() {}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int array[10];
|
||||
array[0] = 0;
|
||||
int (&array_ref)[10] = array;
|
||||
int *p_int0 = &array[0];
|
||||
|
||||
stop(); // Set a breakpoint here
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user