https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/217431
>From 2ad48088a09b26ae8fc0bad1313a6674d3ca92d6 Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <[email protected]> Date: Wed, 19 Aug 2026 21:34:00 +0500 Subject: [PATCH 1/3] [lldb] Redo error handling in ValueObject's CastToBasicType and CastToEnumType --- lldb/include/lldb/ValueObject/ValueObject.h | 4 +- lldb/source/ValueObject/DILEval.cpp | 47 ++++++-- lldb/source/ValueObject/ValueObject.cpp | 112 +++++++----------- .../var-dil/expr/Casts/TestFrameVarDILCast.py | 14 +++ 4 files changed, 94 insertions(+), 83 deletions(-) diff --git a/lldb/include/lldb/ValueObject/ValueObject.h b/lldb/include/lldb/ValueObject/ValueObject.h index c370993d372b7..5d35c30bcf262 100644 --- a/lldb/include/lldb/ValueObject/ValueObject.h +++ b/lldb/include/lldb/ValueObject/ValueObject.h @@ -667,11 +667,11 @@ class ValueObject { // Take a ValueObject that contains a scalar, enum or pointer type, and // cast it to a "basic" type (integer, float or boolean). - lldb::ValueObjectSP CastToBasicType(CompilerType type); + llvm::Expected<lldb::ValueObjectSP> CastToBasicType(CompilerType type); // Take a ValueObject that contain an integer, float or enum, and cast it // to an enum. - lldb::ValueObjectSP CastToEnumType(CompilerType type); + llvm::Expected<lldb::ValueObjectSP> CastToEnumType(CompilerType type); /// If this object represents a C++ class with a vtable, return an object /// that represents the virtual function table. If the object isn't a class diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index d448444b43eba..c196509850a6a 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -88,10 +88,20 @@ Interpreter::UnaryConversion(lldb::ValueObjectSP valobj, uint32_t location) { if (!uint_bit_size) return uint_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); + (in_type.IsSigned() && bitfield_size == *int_bit_size)) { + auto value_or_err = valobj->CastToBasicType(int_type); + if (!value_or_err) + return llvm::make_error<DILDiagnosticError>( + m_expr, llvm::toString(value_or_err.takeError()), location); + return *value_or_err; + } + if (bitfield_size <= *uint_bit_size) { + auto value_or_err = valobj->CastToBasicType(uint_type); + if (!value_or_err) + return llvm::make_error<DILDiagnosticError>( + m_expr, llvm::toString(value_or_err.takeError()), location); + return *value_or_err; + } // Re-create as a const value with the same underlying type Scalar scalar; bool resolved = valobj->ResolveValue(scalar); @@ -107,8 +117,13 @@ Interpreter::UnaryConversion(lldb::ValueObjectSP valobj, uint32_t location) { CompilerType promoted_type = valobj->GetCompilerType().GetPromotedIntegerType(); - if (promoted_type) - return valobj->CastToBasicType(promoted_type); + if (promoted_type) { + auto value_or_err = valobj->CastToBasicType(promoted_type); + if (!value_or_err) + return llvm::make_error<DILDiagnosticError>( + m_expr, llvm::toString(value_or_err.takeError()), location); + return *value_or_err; + } return valobj; } @@ -1933,14 +1948,26 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::Visit(const CastNode &node) { case CastKind::eEnumeration: { // FIXME: is this correct for float vector types? if (op_type.GetTypeInfo() & lldb::eTypeIsFloat || op_type.IsInteger() || - op_type.IsEnumerationType()) - return operand->CastToEnumType(target_type); + op_type.IsEnumerationType()) { + auto value_or_err = operand->CastToEnumType(target_type); + if (!value_or_err) + return llvm::make_error<DILDiagnosticError>( + m_expr, llvm::toString(value_or_err.takeError()), + node.GetLocation()); + return *value_or_err; + } break; } case CastKind::eArithmetic: { if (op_type.IsPointerType() || op_type.IsNullPtrType() || - op_type.IsScalarType() || op_type.IsEnumerationType()) - return operand->CastToBasicType(target_type); + op_type.IsScalarType() || op_type.IsEnumerationType()) { + auto value_or_err = operand->CastToBasicType(target_type); + if (!value_or_err) + return llvm::make_error<DILDiagnosticError>( + m_expr, llvm::toString(value_or_err.takeError()), + node.GetLocation()); + return *value_or_err; + } break; } case CastKind::ePointer: { diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp index 5571507a7d545..39516d3359b1a 100644 --- a/lldb/source/ValueObject/ValueObject.cpp +++ b/lldb/source/ValueObject/ValueObject.cpp @@ -3190,7 +3190,8 @@ ValueObject::CastBaseToDerivedType(CompilerType type, uint64_t offset) { return value->Dereference(error); } -lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) { +llvm::Expected<lldb::ValueObjectSP> +ValueObject::CastToBasicType(CompilerType type) { bool is_scalar = GetCompilerType().IsScalarType(); bool is_enum = GetCompilerType().IsEnumerationType(); bool is_pointer = @@ -3200,14 +3201,11 @@ lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) { ExecutionContext exe_ctx(GetExecutionContextRef()); if (!type.IsScalarType()) - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorString("target type must be a scalar")); + return llvm::createStringError("target type must be a scalar"); if (!is_scalar && !is_enum && !is_pointer) - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorString("argument must be a scalar, enum, or pointer")); + return llvm::createStringError( + "argument must be a scalar, enum, or pointer"); lldb::TargetSP target = GetTargetSP(); uint64_t type_byte_size = 0; @@ -3220,14 +3218,11 @@ lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) { if (is_pointer) { if (!type.IsInteger() && !type.IsBoolean()) - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorString("target type must be an integer or boolean")); + return llvm::createStringError( + "target type must be an integer or boolean"); if (!type.IsBoolean() && type_byte_size < val_byte_size) - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorString( - "target type cannot be smaller than the pointer type")); + return llvm::createStringError( + "target type cannot be smaller than the pointer type"); } if (type.IsBoolean()) { @@ -3242,11 +3237,9 @@ lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) { exe_ctx, type.GetTypeSystem().GetSharedPointer(), !float_value_or_err->isZero(), "result"); else - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorStringWithFormat( - "cannot get value as APFloat: %s", - llvm::toString(float_value_or_err.takeError()).c_str())); + return llvm::createStringErrorV( + "cannot get value as APFloat: {0}", + llvm::toString(float_value_or_err.takeError())); } } @@ -3261,11 +3254,9 @@ lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) { return ValueObject::CreateValueObjectFromAPInt(exe_ctx, ext, type, "result"); } else - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorStringWithFormat( - "cannot get value as APSInt: %s", - llvm::toString(int_value_or_err.takeError()).c_str())); + return llvm::createStringErrorV( + "cannot get value as APSInt: {0}", + llvm::toString(int_value_or_err.takeError())); } else if (is_scalar && is_float) { llvm::APSInt integer(type_byte_size * CHAR_BIT, !type.IsSigned()); bool is_exact; @@ -3278,13 +3269,13 @@ lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) { // Casting floating point values that are out of bounds of the target // type is undefined behaviour. if (status & llvm::APFloatBase::opInvalidOp) - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorStringWithFormat( - "invalid type cast detected: %s", - llvm::toString(float_value_or_err.takeError()).c_str())); + return llvm::createStringError("invalid cast from float to integer"); return ValueObject::CreateValueObjectFromAPInt(exe_ctx, integer, type, "result"); + } else { + return llvm::createStringErrorV( + "cannot get value as APFloat: {0}", + llvm::toString(float_value_or_err.takeError())); } } } @@ -3301,11 +3292,9 @@ lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) { return ValueObject::CreateValueObjectFromAPFloat(exe_ctx, f, type, "result"); } else { - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorStringWithFormat( - "cannot get value as APSInt: %s", - llvm::toString(int_value_or_err.takeError()).c_str())); + return llvm::createStringErrorV( + "cannot get value as APSInt: {0}", + llvm::toString(int_value_or_err.takeError())); } } else { if (is_integer) { @@ -3317,11 +3306,9 @@ lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) { return ValueObject::CreateValueObjectFromAPFloat(exe_ctx, f, type, "result"); } else { - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorStringWithFormat( - "cannot get value as APSInt: %s", - llvm::toString(int_value_or_err.takeError()).c_str())); + return llvm::createStringErrorV( + "cannot get value as APSInt: {0}", + llvm::toString(int_value_or_err.takeError())); } } if (is_float) { @@ -3333,37 +3320,30 @@ lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) { return ValueObject::CreateValueObjectFromAPFloat(exe_ctx, f, type, "result"); } else { - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorStringWithFormat( - "cannot get value as APFloat: %s", - llvm::toString(float_value_or_err.takeError()).c_str())); + return llvm::createStringErrorV( + "cannot get value as APFloat: {0}", + llvm::toString(float_value_or_err.takeError())); } } } } - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorString("Unable to perform requested cast")); + return llvm::createStringError("Unable to perform requested cast"); } -lldb::ValueObjectSP ValueObject::CastToEnumType(CompilerType type) { +llvm::Expected<lldb::ValueObjectSP> +ValueObject::CastToEnumType(CompilerType type) { bool is_enum = GetCompilerType().IsEnumerationType(); bool is_integer = GetCompilerType().IsInteger(); bool is_float = HasFloatingRepresentation(GetCompilerType()); ExecutionContext exe_ctx(GetExecutionContextRef()); if (!is_enum && !is_integer && !is_float) - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorString( - "argument must be an integer, a float, or an enum")); + return llvm::createStringError( + "argument must be an integer, a float, or an enum"); if (!type.IsEnumerationType()) - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorString("target type must be an enum")); + return llvm::createStringError("target type must be an enum"); lldb::TargetSP target = GetTargetSP(); uint64_t byte_size = 0; @@ -3382,17 +3362,12 @@ lldb::ValueObjectSP ValueObject::CastToEnumType(CompilerType type) { // Casting floating point values that are out of bounds of the target // type is undefined behaviour. if (status & llvm::APFloatBase::opInvalidOp) - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorString("invalid cast from float to integer")); + return llvm::createStringError("invalid cast from float to integer"); return ValueObject::CreateValueObjectFromAPInt(exe_ctx, integer, type, "result"); } else - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorStringWithFormatv( - "cannot get value as APFloat: {0}", - llvm::toString(value_or_err.takeError()))); + return llvm::createStringErrorV("cannot get value as APFloat: {0}", + llvm::toString(value_or_err.takeError())); } else { // Get the value as APSInt and extend or truncate it to the requested size. auto value_or_err = GetValueAsAPSInt(); @@ -3401,15 +3376,10 @@ lldb::ValueObjectSP ValueObject::CastToEnumType(CompilerType type) { return ValueObject::CreateValueObjectFromAPInt(exe_ctx, ext, type, "result"); } else - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorStringWithFormat( - "cannot get value as APSInt: %s", - llvm::toString(value_or_err.takeError()).c_str())); + return llvm::createStringErrorV("cannot get value as APSInt: {0}", + llvm::toString(value_or_err.takeError())); } - return ValueObjectConstResult::Create( - exe_ctx.GetBestExecutionContextScope(), - Status::FromErrorString("Cannot perform requested cast")); + return llvm::createStringError("Cannot perform requested cast"); } ValueObject::EvaluationPoint::EvaluationPoint() : m_mod_id(), m_exe_ctx_ref() {} diff --git a/lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py b/lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py index 567981cd670e9..7bde0e91cada8 100644 --- a/lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py +++ b/lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py @@ -322,3 +322,17 @@ def test_type_cast(self): error=True, substrs=["Cast from 'InnerFoo' to 'UnscopedEnum' is not allowed"], ) + + # Check that failed casts output errors with diagnostics + self.expect( + "script lldb.frame.GetValueForVariablePath('+(int) finf')", + substrs=["<user expression>:1:2: invalid cast from float to integer"], + ) + self.expect( + "script lldb.frame.GetValueForVariablePath('+(float) *((int *) 0)')", + substrs=["<user expression>:1:2: cannot get value as APSInt"], + ) + self.expect( + "script lldb.frame.GetValueForVariablePath('+(UnscopedEnum) *((float *) 0)')", + substrs=["<user expression>:1:2: cannot get value as APFloat"], + ) >From 594b4cc35a82418d103e98ae0598d10addd7dc1a Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <[email protected]> Date: Fri, 21 Aug 2026 17:34:29 +0500 Subject: [PATCH 2/3] Revert "[lldb] Redo error handling in ValueObject's CastToBasicType and CastToEnumType" This reverts commit 2ad48088a09b26ae8fc0bad1313a6674d3ca92d6. --- lldb/include/lldb/ValueObject/ValueObject.h | 4 +- lldb/source/ValueObject/DILEval.cpp | 47 ++------ lldb/source/ValueObject/ValueObject.cpp | 112 +++++++++++------- .../var-dil/expr/Casts/TestFrameVarDILCast.py | 14 --- 4 files changed, 83 insertions(+), 94 deletions(-) diff --git a/lldb/include/lldb/ValueObject/ValueObject.h b/lldb/include/lldb/ValueObject/ValueObject.h index 5d35c30bcf262..c370993d372b7 100644 --- a/lldb/include/lldb/ValueObject/ValueObject.h +++ b/lldb/include/lldb/ValueObject/ValueObject.h @@ -667,11 +667,11 @@ class ValueObject { // Take a ValueObject that contains a scalar, enum or pointer type, and // cast it to a "basic" type (integer, float or boolean). - llvm::Expected<lldb::ValueObjectSP> CastToBasicType(CompilerType type); + lldb::ValueObjectSP CastToBasicType(CompilerType type); // Take a ValueObject that contain an integer, float or enum, and cast it // to an enum. - llvm::Expected<lldb::ValueObjectSP> CastToEnumType(CompilerType type); + lldb::ValueObjectSP CastToEnumType(CompilerType type); /// If this object represents a C++ class with a vtable, return an object /// that represents the virtual function table. If the object isn't a class diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index c196509850a6a..d448444b43eba 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -88,20 +88,10 @@ Interpreter::UnaryConversion(lldb::ValueObjectSP valobj, uint32_t location) { if (!uint_bit_size) return uint_bit_size.takeError(); if (bitfield_size < *int_bit_size || - (in_type.IsSigned() && bitfield_size == *int_bit_size)) { - auto value_or_err = valobj->CastToBasicType(int_type); - if (!value_or_err) - return llvm::make_error<DILDiagnosticError>( - m_expr, llvm::toString(value_or_err.takeError()), location); - return *value_or_err; - } - if (bitfield_size <= *uint_bit_size) { - auto value_or_err = valobj->CastToBasicType(uint_type); - if (!value_or_err) - return llvm::make_error<DILDiagnosticError>( - m_expr, llvm::toString(value_or_err.takeError()), location); - return *value_or_err; - } + (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); @@ -117,13 +107,8 @@ Interpreter::UnaryConversion(lldb::ValueObjectSP valobj, uint32_t location) { CompilerType promoted_type = valobj->GetCompilerType().GetPromotedIntegerType(); - if (promoted_type) { - auto value_or_err = valobj->CastToBasicType(promoted_type); - if (!value_or_err) - return llvm::make_error<DILDiagnosticError>( - m_expr, llvm::toString(value_or_err.takeError()), location); - return *value_or_err; - } + if (promoted_type) + return valobj->CastToBasicType(promoted_type); return valobj; } @@ -1948,26 +1933,14 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::Visit(const CastNode &node) { case CastKind::eEnumeration: { // FIXME: is this correct for float vector types? if (op_type.GetTypeInfo() & lldb::eTypeIsFloat || op_type.IsInteger() || - op_type.IsEnumerationType()) { - auto value_or_err = operand->CastToEnumType(target_type); - if (!value_or_err) - return llvm::make_error<DILDiagnosticError>( - m_expr, llvm::toString(value_or_err.takeError()), - node.GetLocation()); - return *value_or_err; - } + op_type.IsEnumerationType()) + return operand->CastToEnumType(target_type); break; } case CastKind::eArithmetic: { if (op_type.IsPointerType() || op_type.IsNullPtrType() || - op_type.IsScalarType() || op_type.IsEnumerationType()) { - auto value_or_err = operand->CastToBasicType(target_type); - if (!value_or_err) - return llvm::make_error<DILDiagnosticError>( - m_expr, llvm::toString(value_or_err.takeError()), - node.GetLocation()); - return *value_or_err; - } + op_type.IsScalarType() || op_type.IsEnumerationType()) + return operand->CastToBasicType(target_type); break; } case CastKind::ePointer: { diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp index 39516d3359b1a..5571507a7d545 100644 --- a/lldb/source/ValueObject/ValueObject.cpp +++ b/lldb/source/ValueObject/ValueObject.cpp @@ -3190,8 +3190,7 @@ ValueObject::CastBaseToDerivedType(CompilerType type, uint64_t offset) { return value->Dereference(error); } -llvm::Expected<lldb::ValueObjectSP> -ValueObject::CastToBasicType(CompilerType type) { +lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) { bool is_scalar = GetCompilerType().IsScalarType(); bool is_enum = GetCompilerType().IsEnumerationType(); bool is_pointer = @@ -3201,11 +3200,14 @@ ValueObject::CastToBasicType(CompilerType type) { ExecutionContext exe_ctx(GetExecutionContextRef()); if (!type.IsScalarType()) - return llvm::createStringError("target type must be a scalar"); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorString("target type must be a scalar")); if (!is_scalar && !is_enum && !is_pointer) - return llvm::createStringError( - "argument must be a scalar, enum, or pointer"); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorString("argument must be a scalar, enum, or pointer")); lldb::TargetSP target = GetTargetSP(); uint64_t type_byte_size = 0; @@ -3218,11 +3220,14 @@ ValueObject::CastToBasicType(CompilerType type) { if (is_pointer) { if (!type.IsInteger() && !type.IsBoolean()) - return llvm::createStringError( - "target type must be an integer or boolean"); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorString("target type must be an integer or boolean")); if (!type.IsBoolean() && type_byte_size < val_byte_size) - return llvm::createStringError( - "target type cannot be smaller than the pointer type"); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorString( + "target type cannot be smaller than the pointer type")); } if (type.IsBoolean()) { @@ -3237,9 +3242,11 @@ ValueObject::CastToBasicType(CompilerType type) { exe_ctx, type.GetTypeSystem().GetSharedPointer(), !float_value_or_err->isZero(), "result"); else - return llvm::createStringErrorV( - "cannot get value as APFloat: {0}", - llvm::toString(float_value_or_err.takeError())); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorStringWithFormat( + "cannot get value as APFloat: %s", + llvm::toString(float_value_or_err.takeError()).c_str())); } } @@ -3254,9 +3261,11 @@ ValueObject::CastToBasicType(CompilerType type) { return ValueObject::CreateValueObjectFromAPInt(exe_ctx, ext, type, "result"); } else - return llvm::createStringErrorV( - "cannot get value as APSInt: {0}", - llvm::toString(int_value_or_err.takeError())); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorStringWithFormat( + "cannot get value as APSInt: %s", + llvm::toString(int_value_or_err.takeError()).c_str())); } else if (is_scalar && is_float) { llvm::APSInt integer(type_byte_size * CHAR_BIT, !type.IsSigned()); bool is_exact; @@ -3269,13 +3278,13 @@ ValueObject::CastToBasicType(CompilerType type) { // Casting floating point values that are out of bounds of the target // type is undefined behaviour. if (status & llvm::APFloatBase::opInvalidOp) - return llvm::createStringError("invalid cast from float to integer"); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorStringWithFormat( + "invalid type cast detected: %s", + llvm::toString(float_value_or_err.takeError()).c_str())); return ValueObject::CreateValueObjectFromAPInt(exe_ctx, integer, type, "result"); - } else { - return llvm::createStringErrorV( - "cannot get value as APFloat: {0}", - llvm::toString(float_value_or_err.takeError())); } } } @@ -3292,9 +3301,11 @@ ValueObject::CastToBasicType(CompilerType type) { return ValueObject::CreateValueObjectFromAPFloat(exe_ctx, f, type, "result"); } else { - return llvm::createStringErrorV( - "cannot get value as APSInt: {0}", - llvm::toString(int_value_or_err.takeError())); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorStringWithFormat( + "cannot get value as APSInt: %s", + llvm::toString(int_value_or_err.takeError()).c_str())); } } else { if (is_integer) { @@ -3306,9 +3317,11 @@ ValueObject::CastToBasicType(CompilerType type) { return ValueObject::CreateValueObjectFromAPFloat(exe_ctx, f, type, "result"); } else { - return llvm::createStringErrorV( - "cannot get value as APSInt: {0}", - llvm::toString(int_value_or_err.takeError())); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorStringWithFormat( + "cannot get value as APSInt: %s", + llvm::toString(int_value_or_err.takeError()).c_str())); } } if (is_float) { @@ -3320,30 +3333,37 @@ ValueObject::CastToBasicType(CompilerType type) { return ValueObject::CreateValueObjectFromAPFloat(exe_ctx, f, type, "result"); } else { - return llvm::createStringErrorV( - "cannot get value as APFloat: {0}", - llvm::toString(float_value_or_err.takeError())); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorStringWithFormat( + "cannot get value as APFloat: %s", + llvm::toString(float_value_or_err.takeError()).c_str())); } } } } - return llvm::createStringError("Unable to perform requested cast"); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorString("Unable to perform requested cast")); } -llvm::Expected<lldb::ValueObjectSP> -ValueObject::CastToEnumType(CompilerType type) { +lldb::ValueObjectSP ValueObject::CastToEnumType(CompilerType type) { bool is_enum = GetCompilerType().IsEnumerationType(); bool is_integer = GetCompilerType().IsInteger(); bool is_float = HasFloatingRepresentation(GetCompilerType()); ExecutionContext exe_ctx(GetExecutionContextRef()); if (!is_enum && !is_integer && !is_float) - return llvm::createStringError( - "argument must be an integer, a float, or an enum"); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorString( + "argument must be an integer, a float, or an enum")); if (!type.IsEnumerationType()) - return llvm::createStringError("target type must be an enum"); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorString("target type must be an enum")); lldb::TargetSP target = GetTargetSP(); uint64_t byte_size = 0; @@ -3362,12 +3382,17 @@ ValueObject::CastToEnumType(CompilerType type) { // Casting floating point values that are out of bounds of the target // type is undefined behaviour. if (status & llvm::APFloatBase::opInvalidOp) - return llvm::createStringError("invalid cast from float to integer"); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorString("invalid cast from float to integer")); return ValueObject::CreateValueObjectFromAPInt(exe_ctx, integer, type, "result"); } else - return llvm::createStringErrorV("cannot get value as APFloat: {0}", - llvm::toString(value_or_err.takeError())); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorStringWithFormatv( + "cannot get value as APFloat: {0}", + llvm::toString(value_or_err.takeError()))); } else { // Get the value as APSInt and extend or truncate it to the requested size. auto value_or_err = GetValueAsAPSInt(); @@ -3376,10 +3401,15 @@ ValueObject::CastToEnumType(CompilerType type) { return ValueObject::CreateValueObjectFromAPInt(exe_ctx, ext, type, "result"); } else - return llvm::createStringErrorV("cannot get value as APSInt: {0}", - llvm::toString(value_or_err.takeError())); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorStringWithFormat( + "cannot get value as APSInt: %s", + llvm::toString(value_or_err.takeError()).c_str())); } - return llvm::createStringError("Cannot perform requested cast"); + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorString("Cannot perform requested cast")); } ValueObject::EvaluationPoint::EvaluationPoint() : m_mod_id(), m_exe_ctx_ref() {} diff --git a/lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py b/lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py index 7bde0e91cada8..567981cd670e9 100644 --- a/lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py +++ b/lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py @@ -322,17 +322,3 @@ def test_type_cast(self): error=True, substrs=["Cast from 'InnerFoo' to 'UnscopedEnum' is not allowed"], ) - - # Check that failed casts output errors with diagnostics - self.expect( - "script lldb.frame.GetValueForVariablePath('+(int) finf')", - substrs=["<user expression>:1:2: invalid cast from float to integer"], - ) - self.expect( - "script lldb.frame.GetValueForVariablePath('+(float) *((int *) 0)')", - substrs=["<user expression>:1:2: cannot get value as APSInt"], - ) - self.expect( - "script lldb.frame.GetValueForVariablePath('+(UnscopedEnum) *((float *) 0)')", - substrs=["<user expression>:1:2: cannot get value as APFloat"], - ) >From 15909773d9e30ca4d6a9f92fcbc8d263395e74d0 Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <[email protected]> Date: Fri, 21 Aug 2026 18:04:12 +0500 Subject: [PATCH 3/3] [lldb] Handle errors of failed casts in DIL --- lldb/source/ValueObject/DILEval.cpp | 47 ++++++++++++++----- lldb/source/ValueObject/ValueObject.cpp | 9 +++- .../var-dil/expr/Casts/TestFrameVarDILCast.py | 38 +++++++++++++++ 3 files changed, 81 insertions(+), 13 deletions(-) diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index d448444b43eba..2995abb1bec2b 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -88,10 +88,20 @@ Interpreter::UnaryConversion(lldb::ValueObjectSP valobj, uint32_t location) { if (!uint_bit_size) return uint_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); + (in_type.IsSigned() && bitfield_size == *int_bit_size)) { + auto result = valobj->CastToBasicType(int_type); + if (result->GetError().Fail()) + return llvm::make_error<DILDiagnosticError>( + m_expr, result->GetError().AsCString(), location); + return result; + } + if (bitfield_size <= *uint_bit_size) { + auto result = valobj->CastToBasicType(uint_type); + if (result->GetError().Fail()) + return llvm::make_error<DILDiagnosticError>( + m_expr, result->GetError().AsCString(), location); + return result; + } // Re-create as a const value with the same underlying type Scalar scalar; bool resolved = valobj->ResolveValue(scalar); @@ -107,8 +117,13 @@ Interpreter::UnaryConversion(lldb::ValueObjectSP valobj, uint32_t location) { CompilerType promoted_type = valobj->GetCompilerType().GetPromotedIntegerType(); - if (promoted_type) - return valobj->CastToBasicType(promoted_type); + if (promoted_type) { + auto result = valobj->CastToBasicType(promoted_type); + if (result->GetError().Fail()) + return llvm::make_error<DILDiagnosticError>( + m_expr, result->GetError().AsCString(), location); + return result; + } return valobj; } @@ -1929,18 +1944,19 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::Visit(const CastNode &node) { node.GetLocation()); } + lldb::ValueObjectSP result; switch (cast_kind) { case CastKind::eEnumeration: { // FIXME: is this correct for float vector types? if (op_type.GetTypeInfo() & lldb::eTypeIsFloat || op_type.IsInteger() || op_type.IsEnumerationType()) - return operand->CastToEnumType(target_type); + result = operand->CastToEnumType(target_type); break; } case CastKind::eArithmetic: { if (op_type.IsPointerType() || op_type.IsNullPtrType() || op_type.IsScalarType() || op_type.IsEnumerationType()) - return operand->CastToBasicType(target_type); + result = operand->CastToBasicType(target_type); break; } case CastKind::ePointer: { @@ -1950,15 +1966,24 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::Visit(const CastNode &node) { : operand->GetValueAsUnsigned(0)); llvm::StringRef name = "result"; ExecutionContext exe_ctx(m_target.get(), false); - return ValueObject::CreateValueObjectFromAddress(name, addr, exe_ctx, - target_type, - /* do_deref */ false); + result = ValueObject::CreateValueObjectFromAddress(name, addr, exe_ctx, + target_type, + /* do_deref */ false); + break; } case CastKind::eNone: { return lldb::ValueObjectSP(); } } // switch + if (result) { + // If cast failed, retrieve the error message from the result. + if (result->GetError().Fail()) + return llvm::make_error<DILDiagnosticError>( + m_expr, result->GetError().AsCString(), node.GetLocation()); + return result; + } + std::string errMsg = llvm::formatv("unable to cast from '{0}' to '{1}'", op_type.TypeDescription(), target_type.TypeDescription()); diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp index 5571507a7d545..b55ef2dd3b0d1 100644 --- a/lldb/source/ValueObject/ValueObject.cpp +++ b/lldb/source/ValueObject/ValueObject.cpp @@ -3281,10 +3281,15 @@ lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) { return ValueObjectConstResult::Create( exe_ctx.GetBestExecutionContextScope(), Status::FromErrorStringWithFormat( - "invalid type cast detected: %s", - llvm::toString(float_value_or_err.takeError()).c_str())); + "invalid cast from float to integer")); return ValueObject::CreateValueObjectFromAPInt(exe_ctx, integer, type, "result"); + } else { + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status::FromErrorStringWithFormat( + "cannot get value as APFloat: %s", + llvm::toString(float_value_or_err.takeError()).c_str())); } } } diff --git a/lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py b/lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py index 567981cd670e9..9f56149d94456 100644 --- a/lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py +++ b/lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py @@ -322,3 +322,41 @@ def test_type_cast(self): error=True, substrs=["Cast from 'InnerFoo' to 'UnscopedEnum' is not allowed"], ) + + # Check that failed casts output errors with diagnostics + self.expect( + "script lldb.frame.GetValueForVariablePath('+(bool) *((float *) 0)')", + substrs=["<user expression>:1:2: cannot get value as APFloat"], + ) + self.expect( + "script lldb.frame.GetValueForVariablePath('+(int) *((int *) 0)')", + substrs=["<user expression>:1:2: cannot get value as APSInt"], + ) + self.expect( + "script lldb.frame.GetValueForVariablePath('+(int) finf')", + substrs=["<user expression>:1:2: invalid cast from float to integer"], + ) + self.expect( + "script lldb.frame.GetValueForVariablePath('+(int) *((float *) 0)')", + substrs=["<user expression>:1:2: cannot get value as APFloat"], + ) + self.expect( + "script lldb.frame.GetValueForVariablePath('+(float) *((int *) 0)')", + substrs=["<user expression>:1:2: cannot get value as APSInt"], + ) + self.expect( + "script lldb.frame.GetValueForVariablePath('+(float) *((float *) 0)')", + substrs=["<user expression>:1:2: cannot get value as APFloat"], + ) + self.expect( + "script lldb.frame.GetValueForVariablePath('+(UnscopedEnum) finf')", + substrs=["<user expression>:1:2: invalid cast from float to integer"], + ) + self.expect( + "script lldb.frame.GetValueForVariablePath('+(UnscopedEnum) *((float *) 0)')", + substrs=["<user expression>:1:2: cannot get value as APFloat"], + ) + self.expect( + "script lldb.frame.GetValueForVariablePath('+(UnscopedEnum) *((int *) 0)')", + substrs=["<user expression>:1:2: cannot get value as APSInt"], + ) _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
