[Lldb-commits] [lldb] [LLDB] Add type casting to DIL. (PR #159500)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Oct 3 16:07:23 PDT 2025
https://github.com/cmtice updated https://github.com/llvm/llvm-project/pull/159500
>From bbacb825638d18f052dfeec253c765001a872229 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Wed, 17 Sep 2025 20:21:52 -0700
Subject: [PATCH 1/7] [LLDB] Add type casting to DIL.
This adds basic c-style type casting to DIL. It handles basic
built-in types: bool, char, short, int, long, double, float, and void.
It also handles user-defined types (e.g. class names, typedefs, etc.).
It does NOT handle C++ templates at the moment. Not sure if this is
something we would want to add to DIL later or not. DIL will not
be supporting C++-specific-style casts (static_cast<>, reinterpret_cast<>,
or dynamic_cast<>).
This PR adds quite a bit of type-parsing, which must happen in the
parser, to resolve ambiguity ("is this thing I'm looking at a type cast
or just an expression in parentheses?").
I'd be happy to break this up into smaller PRs if someone could suggest
a reasonable way to break it up.
---
lldb/docs/dil-expr-lang.ebnf | 32 +-
lldb/include/lldb/ValueObject/DILAST.h | 41 ++
lldb/include/lldb/ValueObject/DILEval.h | 7 +
lldb/include/lldb/ValueObject/DILParser.h | 133 ++++
lldb/source/ValueObject/DILAST.cpp | 4 +
lldb/source/ValueObject/DILEval.cpp | 285 +++++++-
lldb/source/ValueObject/DILParser.cpp | 634 +++++++++++++++++-
.../LocalVars/TestFrameVarDILLocalVars.py | 1 +
.../frame/var-dil/expr/CStyleCast/Makefile | 6 +
.../CStyleCast/TestFrameVarDILCStyleCast.py | 233 +++++++
.../frame/var-dil/expr/CStyleCast/main.cpp | 81 +++
11 files changed, 1439 insertions(+), 18 deletions(-)
create mode 100644 lldb/test/API/commands/frame/var-dil/expr/CStyleCast/Makefile
create mode 100644 lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py
create mode 100644 lldb/test/API/commands/frame/var-dil/expr/CStyleCast/main.cpp
diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index 67328939ba420..4a66734e75fec 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -3,10 +3,13 @@
(* This is currently a subset of the final DIL Language, matching the current
DIL implementation. *)
-expression = unary_expression ;
+expression = cast_expression;
+
+cast_expression = unary_expression
+ | "(" type_id ")" cast_expression;
unary_expression = postfix_expression
- | unary_operator expression ;
+ | unary_operator cast_expression ;
unary_operator = "*" | "&" ;
@@ -41,6 +44,31 @@ nested_name_specifier = type_name "::"
| namespace_name '::'
| nested_name_specifier identifier "::" ;
+type_id = type_specifier_seq [abstract_declarator] ;
+
+type_specifier_seq = type_specifier [type_specifier];
+
+type_specifier = ["::"] [nested_name_specifier] type_name;
+ | "char"
+ | "bool"
+ | "short"
+ | "int"
+ | "long"
+ | "signed"
+ | "unsigned"
+ | "float"
+ | "double"
+ | "void" ;
+
+nested_name_specifier = type_name "::"
+ | namespace_name "::"
+ | nested_name_specifier identifier "::" ;
+
+abstract_declarator = ptr_operator [abstract_declarator] ;
+
+ptr_operator = "*"
+ | "&";
+
type_name = class_name
| enum_name
| typedef_name;
diff --git a/lldb/include/lldb/ValueObject/DILAST.h b/lldb/include/lldb/ValueObject/DILAST.h
index 1d10755c46e39..bbaad28d55735 100644
--- a/lldb/include/lldb/ValueObject/DILAST.h
+++ b/lldb/include/lldb/ValueObject/DILAST.h
@@ -20,6 +20,7 @@ namespace lldb_private::dil {
enum class NodeKind {
eArraySubscriptNode,
eBitExtractionNode,
+ eCStyleCastNode,
eErrorNode,
eFloatLiteralNode,
eIdentifierNode,
@@ -28,6 +29,21 @@ enum class NodeKind {
eUnaryOpNode,
};
+/// The C-Style casts allowed by DIL.
+enum class CStyleCastKind {
+ eEnumeration,
+ eNullptr,
+ eReference,
+ eNone,
+};
+
+/// Promotions for C-Style casts in DIL.
+enum class CastPromoKind {
+ eArithmetic,
+ ePointer,
+ eNone,
+};
+
/// The Unary operators recognized by DIL.
enum class UnaryOpKind {
AddrOf, // "&"
@@ -226,6 +242,29 @@ class FloatLiteralNode : public ASTNode {
llvm::APFloat m_value;
};
+class CStyleCastNode : public ASTNode {
+public:
+ CStyleCastNode(uint32_t location, CompilerType type, ASTNodeUP operand,
+ CStyleCastKind kind)
+ : ASTNode(location, NodeKind::eCStyleCastNode), m_type(type),
+ m_operand(std::move(operand)), m_cast_kind(kind) {}
+
+ llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
+
+ CompilerType GetType() const { return m_type; }
+ ASTNode *GetOperand() const { return m_operand.get(); }
+ CStyleCastKind GetCastKind() const { return m_cast_kind; }
+
+ static bool classof(const ASTNode *node) {
+ return node->GetKind() == NodeKind::eCStyleCastNode;
+ }
+
+private:
+ CompilerType m_type;
+ ASTNodeUP m_operand;
+ CStyleCastKind m_cast_kind;
+};
+
/// This class contains one Visit method for each specialized type of
/// DIL AST node. The Visit methods are used to dispatch a DIL AST node to
/// the correct function in the DIL expression evaluator for evaluating that
@@ -247,6 +286,8 @@ class Visitor {
Visit(const IntegerLiteralNode *node) = 0;
virtual llvm::Expected<lldb::ValueObjectSP>
Visit(const FloatLiteralNode *node) = 0;
+ virtual llvm::Expected<lldb::ValueObjectSP>
+ Visit(const CStyleCastNode *node) = 0;
};
} // namespace lldb_private::dil
diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h
index 5a48c2c989f4d..3d4ef021cbc6f 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -58,12 +58,19 @@ class Interpreter : Visitor {
Visit(const IntegerLiteralNode *node) override;
llvm::Expected<lldb::ValueObjectSP>
Visit(const FloatLiteralNode *node) override;
+ llvm::Expected<lldb::ValueObjectSP>
+ Visit(const CStyleCastNode *node) override;
llvm::Expected<CompilerType>
PickIntegerType(lldb::TypeSystemSP type_system,
std::shared_ptr<ExecutionContextScope> ctx,
const IntegerLiteralNode *literal);
+ llvm::Expected<CompilerType>
+ VerifyCStyleCastType(lldb::ValueObjectSP &operand, CompilerType &op_type,
+ CompilerType target_type, CastPromoKind &promo_kind,
+ CStyleCastKind &cast_kind, int location);
+
// Used by the interpreter to create objects, perform casts, etc.
lldb::TargetSP m_target;
llvm::StringRef m_expr;
diff --git a/lldb/include/lldb/ValueObject/DILParser.h b/lldb/include/lldb/ValueObject/DILParser.h
index 90df109337dcf..081711d26439d 100644
--- a/lldb/include/lldb/ValueObject/DILParser.h
+++ b/lldb/include/lldb/ValueObject/DILParser.h
@@ -10,6 +10,7 @@
#define LLDB_VALUEOBJECT_DILPARSER_H
#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/StackFrame.h"
#include "lldb/Utility/DiagnosticsRendering.h"
#include "lldb/Utility/Status.h"
#include "lldb/ValueObject/DILAST.h"
@@ -31,6 +32,9 @@ enum class ErrorCode : unsigned char {
kUnknown,
};
+llvm::Expected<lldb::TypeSystemSP>
+DILGetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx);
+
// The following is modeled on class OptionParseError.
class DILDiagnosticError
: public llvm::ErrorInfo<DILDiagnosticError, DiagnosticError> {
@@ -55,6 +59,61 @@ class DILDiagnosticError
std::string message() const override { return m_detail.rendered; }
};
+/// TypeDeclaration builds information about the literal type definition as
+/// type is being parsed. It doesn't perform semantic analysis for non-basic
+/// types -- e.g. "char&&&" is a valid type declaration.
+/// NOTE: CV qualifiers are ignored.
+class TypeDeclaration {
+public:
+ enum class TypeSpecifier {
+ kBool,
+ kChar,
+ kDouble,
+ kFloat,
+ kInt,
+ kLong,
+ kLongDouble,
+ kLongLong,
+ kShort,
+ kUnknown,
+ kVoid,
+ };
+
+ enum class SignSpecifier {
+ kUnknown,
+ kSigned,
+ kUnsigned,
+ };
+
+ bool IsEmpty() const { return !m_is_builtin && !m_is_user_type; }
+
+ lldb::BasicType GetBasicType() const;
+
+public:
+ // Indicates user-defined typename (e.g. "MyClass", "MyTmpl<int>").
+ std::string m_user_typename;
+
+ // Basic type specifier ("void", "char", "intr", "float", "long long", etc.).
+ TypeSpecifier m_type_specifier = TypeSpecifier::kUnknown;
+
+ // Signedness specifier ("signed", "unsigned").
+ SignSpecifier m_sign_specifier = SignSpecifier::kUnknown;
+
+ // Does the type declaration includes "int" specifier?
+ // This is different than `type_specifier_` and is used to detect "int"
+ // duplication for types that can be combined with "int" specifier (e.g.
+ // "short int", "long int").
+ bool m_has_int_specifier = false;
+
+ // Indicates whether there was an error during parsing.
+ bool m_has_error = false;
+
+ // Indicates whether this declaration describes a builtin type.
+ bool m_is_builtin = false;
+
+ // Indicates whether this declaration describes a user type.
+ bool m_is_user_type = false;
+}; // class TypeDeclaration
/// Pure recursive descent parser for C++ like expressions.
/// EBNF grammar for the parser is described in lldb/docs/dil-expr-lang.ebnf
@@ -100,10 +159,22 @@ class DILParser {
ASTNodeUP ParseIntegerLiteral();
ASTNodeUP ParseFloatingPointLiteral();
+ ASTNodeUP ParseCastExpression();
+ std::optional<CompilerType> ParseTypeId(bool must_be_type_id = false);
+ void ParseTypeSpecifierSeq(TypeDeclaration *type_decl);
+ bool ParseTypeSpecifier(TypeDeclaration *type_decl);
+ std::string ParseTypeName();
+ CompilerType ResolveTypeDeclarators(CompilerType type,
+ const std::vector<Token> &ptr_operators);
+ bool IsSimpleTypeSpecifierKeyword(Token token) const;
+ bool HandleSimpleTypeSpecifier(TypeDeclaration *type_decl);
+
void BailOut(const std::string &error, uint32_t loc, uint16_t err_len);
void Expect(Token::Kind kind);
+ void ExpectOneOf(std::vector<Token::Kind> kinds_vec);
+
void TentativeParsingRollback(uint32_t saved_idx) {
if (m_error)
llvm::consumeError(std::move(m_error));
@@ -132,4 +203,66 @@ class DILParser {
} // namespace lldb_private::dil
+namespace llvm {
+template <>
+struct format_provider<lldb_private::dil::TypeDeclaration::TypeSpecifier> {
+ static void format(const lldb_private::dil::TypeDeclaration::TypeSpecifier &t,
+ raw_ostream &OS, llvm::StringRef Options) {
+ switch (t) {
+ case lldb_private::dil::TypeDeclaration::TypeSpecifier::kVoid:
+ OS << "void";
+ break;
+ case lldb_private::dil::TypeDeclaration::TypeSpecifier::kBool:
+ OS << "bool";
+ break;
+ case lldb_private::dil::TypeDeclaration::TypeSpecifier::kChar:
+ OS << "char";
+ break;
+ case lldb_private::dil::TypeDeclaration::TypeSpecifier::kInt:
+ OS << "int";
+ break;
+ case lldb_private::dil::TypeDeclaration::TypeSpecifier::kFloat:
+ OS << "float";
+ break;
+ case lldb_private::dil::TypeDeclaration::TypeSpecifier::kShort:
+ OS << "short";
+ break;
+ case lldb_private::dil::TypeDeclaration::TypeSpecifier::kLong:
+ OS << "long";
+ break;
+ case lldb_private::dil::TypeDeclaration::TypeSpecifier::kLongLong:
+ OS << "long long";
+ break;
+ case lldb_private::dil::TypeDeclaration::TypeSpecifier::kDouble:
+ OS << "double";
+ break;
+ case lldb_private::dil::TypeDeclaration::TypeSpecifier::kLongDouble:
+ OS << "long double";
+ break;
+ default:
+ OS << "invalid type specifier";
+ break;
+ }
+ }
+};
+
+template <>
+struct format_provider<lldb_private::dil::TypeDeclaration::SignSpecifier> {
+ static void format(const lldb_private::dil::TypeDeclaration::SignSpecifier &t,
+ raw_ostream &OS, llvm::StringRef Options) {
+ switch (t) {
+ case lldb_private::dil::TypeDeclaration::SignSpecifier::kSigned:
+ OS << "signed";
+ break;
+ case lldb_private::dil::TypeDeclaration::SignSpecifier::kUnsigned:
+ OS << "unsigned";
+ break;
+ default:
+ OS << "invalid sign specifier";
+ break;
+ }
+ }
+};
+} // namespace llvm
+
#endif // LLDB_VALUEOBJECT_DILPARSER_H
diff --git a/lldb/source/ValueObject/DILAST.cpp b/lldb/source/ValueObject/DILAST.cpp
index 70564663a62cd..f8afd9d7bd50a 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -46,4 +46,8 @@ llvm::Expected<lldb::ValueObjectSP> FloatLiteralNode::Accept(Visitor *v) const {
return v->Visit(this);
}
+llvm::Expected<lldb::ValueObjectSP> CStyleCastNode::Accept(Visitor *v) const {
+ return v->Visit(this);
+}
+
} // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index c6cf41ee9e9ee..05bcc25d2b9f2 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -13,6 +13,7 @@
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/ValueObject/DILAST.h"
+#include "lldb/ValueObject/DILParser.h"
#include "lldb/ValueObject/ValueObject.h"
#include "lldb/ValueObject/ValueObjectRegister.h"
#include "lldb/ValueObject/ValueObjectVariable.h"
@@ -21,6 +22,42 @@
namespace lldb_private::dil {
+lldb::ValueObjectSP
+GetDynamicOrSyntheticValue(lldb::ValueObjectSP in_valobj_sp,
+ lldb::DynamicValueType use_dynamic,
+ bool use_synthetic) {
+ Status error;
+ if (!in_valobj_sp) {
+ error = Status("invalid value object");
+ return in_valobj_sp;
+ }
+ lldb::ValueObjectSP value_sp = in_valobj_sp;
+ Target *target = value_sp->GetTargetSP().get();
+ // If this ValueObject holds an error, then it is valuable for that.
+ if (value_sp->GetError().Fail())
+ return value_sp;
+
+ if (!target)
+ return lldb::ValueObjectSP();
+
+ if (use_dynamic != lldb::eNoDynamicValues) {
+ lldb::ValueObjectSP dynamic_sp = value_sp->GetDynamicValue(use_dynamic);
+ if (dynamic_sp)
+ value_sp = dynamic_sp;
+ }
+
+ if (use_synthetic) {
+ lldb::ValueObjectSP synthetic_sp = value_sp->GetSyntheticValue();
+ if (synthetic_sp)
+ value_sp = synthetic_sp;
+ }
+
+ if (!value_sp)
+ error = Status("invalid value object");
+
+ return value_sp;
+}
+
static lldb::VariableSP DILFindVariable(ConstString name,
VariableList &variable_list) {
lldb::VariableSP exact_match;
@@ -499,16 +536,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)
@@ -559,7 +586,7 @@ Interpreter::PickIntegerType(lldb::TypeSystemSP type_system,
llvm::Expected<lldb::ValueObjectSP>
Interpreter::Visit(const IntegerLiteralNode *node) {
llvm::Expected<lldb::TypeSystemSP> type_system =
- GetTypeSystemFromCU(m_exe_ctx_scope);
+ DILGetTypeSystemFromCU(m_exe_ctx_scope);
if (!type_system)
return type_system.takeError();
@@ -583,7 +610,7 @@ Interpreter::Visit(const IntegerLiteralNode *node) {
llvm::Expected<lldb::ValueObjectSP>
Interpreter::Visit(const FloatLiteralNode *node) {
llvm::Expected<lldb::TypeSystemSP> type_system =
- GetTypeSystemFromCU(m_exe_ctx_scope);
+ DILGetTypeSystemFromCU(m_exe_ctx_scope);
if (!type_system)
return type_system.takeError();
@@ -602,4 +629,238 @@ Interpreter::Visit(const FloatLiteralNode *node) {
"result");
}
+llvm::Expected<CompilerType> Interpreter::VerifyCStyleCastType(
+ lldb::ValueObjectSP &operand, CompilerType &op_type,
+ CompilerType target_type, CastPromoKind &promo_kind,
+ CStyleCastKind &cast_kind, int location) {
+
+ promo_kind = CastPromoKind::eNone;
+ if (op_type.IsReferenceType())
+ op_type = op_type.GetNonReferenceType();
+ if (target_type.IsScalarType()) {
+ if (op_type.IsArrayType()) {
+ // Do array-to-pointer conversion.
+ CompilerType deref_type =
+ op_type.IsReferenceType() ? op_type.GetNonReferenceType() : op_type;
+ CompilerType result_type =
+ deref_type.GetArrayElementType(nullptr).GetPointerType();
+ uint64_t addr = operand->GetLoadAddress();
+ llvm::StringRef name = operand->GetName().GetStringRef();
+ operand = ValueObject::CreateValueObjectFromAddress(
+ name, addr, m_exe_ctx_scope, result_type, /*do_deref=*/false);
+ op_type = result_type;
+ }
+
+ if (op_type.IsPointerType() || op_type.IsNullPtrType()) {
+ // C-style cast from pointer to float/double is not allowed.
+ if (target_type.IsFloat()) {
+ std::string errMsg = llvm::formatv(
+ "C-style cast from {0} to {1} is not allowed",
+ op_type.TypeDescription(), target_type.TypeDescription());
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, std::move(errMsg), location,
+ op_type.TypeDescription().length());
+ }
+ // Casting pointer to bool is valid. Otherwise check if the result type
+ // is at least as big as the pointer size.
+ uint64_t type_byte_size = 0;
+ uint64_t rhs_type_byte_size = 0;
+ if (auto temp = target_type.GetByteSize(m_exe_ctx_scope.get()))
+ // type_byte_size = temp.value();
+ type_byte_size = *temp;
+ if (auto temp = op_type.GetByteSize(m_exe_ctx_scope.get()))
+ // rhs_type_byte_size = temp.value();
+ rhs_type_byte_size = *temp;
+ if (!target_type.IsBoolean() && type_byte_size < rhs_type_byte_size) {
+ std::string errMsg = llvm::formatv(
+ "cast from pointer to smaller type {0} loses information",
+ target_type.TypeDescription());
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, std::move(errMsg), location,
+ op_type.TypeDescription().length());
+ }
+ } else if (!op_type.IsScalarType() && !op_type.IsEnumerationType()) {
+ // Otherwise accept only arithmetic types and enums.
+ std::string errMsg = llvm::formatv(
+ "cannot convert {0} to {1} without a conversion operator",
+ op_type.TypeDescription(), target_type.TypeDescription());
+
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, std::move(errMsg), location,
+ op_type.TypeDescription().length());
+ }
+ promo_kind = CastPromoKind::eArithmetic;
+ } else if (target_type.IsEnumerationType()) {
+ // Cast to enum type.
+ if (!op_type.IsScalarType() && !op_type.IsEnumerationType()) {
+ std::string errMsg = llvm::formatv(
+ "C-style cast from {0} to {1} is not allowed",
+ op_type.TypeDescription(), target_type.TypeDescription());
+
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, std::move(errMsg), location,
+ op_type.TypeDescription().length());
+ }
+ cast_kind = CStyleCastKind::eEnumeration;
+
+ } else if (target_type.IsPointerType()) {
+ if (!op_type.IsInteger() && !op_type.IsEnumerationType() &&
+ !op_type.IsArrayType() && !op_type.IsPointerType() &&
+ !op_type.IsNullPtrType()) {
+ std::string errMsg = llvm::formatv(
+ "cannot cast from type {0} to pointer type {1}",
+ op_type.TypeDescription(), target_type.TypeDescription());
+
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, std::move(errMsg), location,
+ op_type.TypeDescription().length());
+ }
+ promo_kind = CastPromoKind::ePointer;
+
+ } else if (target_type.IsNullPtrType()) {
+ // Cast to nullptr type.
+ bool is_signed;
+ if (!target_type.IsNullPtrType() &&
+ (!operand->IsIntegerType(is_signed) ||
+ (is_signed && operand->GetValueAsSigned(0) != 0) ||
+ (!is_signed && operand->GetValueAsUnsigned(0) != 0))) {
+ std::string errMsg = llvm::formatv(
+ "C-style cast from {0} to {1} is not allowed",
+ op_type.TypeDescription(), target_type.TypeDescription());
+
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, std::move(errMsg), location,
+ op_type.TypeDescription().length());
+ }
+ cast_kind = CStyleCastKind::eNullptr;
+
+ } else if (target_type.IsReferenceType()) {
+ // Cast to a reference type.
+ cast_kind = CStyleCastKind::eReference;
+ } else {
+ // Unsupported cast.
+ std::string errMsg =
+ llvm::formatv("casting of {0} to {1} is not implemented yet",
+ op_type.TypeDescription(), target_type.TypeDescription());
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, std::move(errMsg), location,
+ op_type.TypeDescription().length());
+ }
+
+ return target_type;
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::Visit(const CStyleCastNode *node) {
+ auto operand_or_err = Evaluate(node->GetOperand());
+ if (!operand_or_err)
+ return operand_or_err;
+
+ lldb::ValueObjectSP operand = *operand_or_err;
+ CompilerType op_type = operand->GetCompilerType();
+ CStyleCastKind cast_kind = CStyleCastKind::eNone;
+ CastPromoKind promo_kind = CastPromoKind::eNone;
+
+ auto type_or_err =
+ VerifyCStyleCastType(operand, op_type, node->GetType(), promo_kind,
+ cast_kind, node->GetLocation());
+ if (!type_or_err)
+ return type_or_err.takeError();
+
+ CompilerType target_type = *type_or_err;
+ if (op_type.IsReferenceType()) {
+ Status error;
+ operand = operand->Dereference(error);
+ if (error.Fail())
+ return llvm::make_error<DILDiagnosticError>(m_expr, error.AsCString(),
+ node->GetLocation());
+ }
+
+ switch (cast_kind) {
+ case CStyleCastKind::eEnumeration: {
+ if (!target_type.IsEnumerationType()) {
+ std::string errMsg = "invalid ast: target type should be an enumeration.";
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+ node->GetLocation());
+ }
+ if (op_type.IsFloat())
+ return operand->CastToEnumType(target_type);
+
+ if (op_type.IsInteger() || op_type.IsEnumerationType())
+ return operand->CastToEnumType(target_type);
+
+ std::string errMsg =
+ "invalid ast: operand is not convertible to enumeration type";
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+ node->GetLocation());
+ // return error.ToError();
+ }
+ case CStyleCastKind::eNullptr: {
+ if (target_type.GetCanonicalType().GetBasicTypeEnumeration() !=
+ lldb::eBasicTypeNullPtr) {
+ std::string errMsg = "invalid ast: target type should be a nullptr_t.";
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+ node->GetLocation());
+ }
+ return ValueObject::CreateValueObjectFromNullptr(m_target, target_type,
+ "result");
+ }
+ case CStyleCastKind::eReference: {
+ lldb::ValueObjectSP operand_sp(
+ GetDynamicOrSyntheticValue(operand, m_use_dynamic, m_use_synthetic));
+ return lldb::ValueObjectSP(
+ operand_sp->Cast(target_type.GetNonReferenceType()));
+ }
+ case CStyleCastKind::eNone: {
+ switch (promo_kind) {
+ case CastPromoKind::eArithmetic: {
+ if (target_type.GetCanonicalType().GetBasicTypeEnumeration() ==
+ lldb::eBasicTypeInvalid) {
+ std::string errMsg = "invalid ast: target type should be a basic type.";
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+ node->GetLocation());
+ }
+ // Pick an appropriate cast.
+ if (op_type.IsPointerType() || op_type.IsNullPtrType()) {
+ return operand->CastToBasicType(target_type);
+ }
+ if (op_type.IsScalarType()) {
+ return operand->CastToBasicType(target_type);
+ }
+ if (op_type.IsEnumerationType()) {
+ return operand->CastToBasicType(target_type);
+ }
+ std::string errMsg =
+ "invalid ast: operand is not convertible to arithmetic type";
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+ node->GetLocation());
+ }
+ case CastPromoKind::ePointer: {
+ if (!target_type.IsPointerType()) {
+ std::string errMsg = "invalid ast: target type should be a pointer";
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+ node->GetLocation());
+ }
+ uint64_t addr =
+ op_type.IsArrayType()
+ ? operand->GetLoadAddress()
+ : (op_type.IsSigned() ? operand->GetValueAsSigned(0)
+ : 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);
+ }
+ case CastPromoKind::eNone: {
+ return lldb::ValueObjectSP();
+ }
+ } // switch promo_kind
+ } // case CStyleCastKind::eNone
+ } // switch cast_kind
+ std::string errMsg = "invalid ast: unexpected c-style cast kind";
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+ node->GetLocation());
+}
+
} // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index 8c4f7fdb25bea..578ee99053201 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -12,7 +12,9 @@
//===----------------------------------------------------------------------===//
#include "lldb/ValueObject/DILParser.h"
+#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Utility/DiagnosticsRendering.h"
#include "lldb/ValueObject/DILAST.h"
#include "lldb/ValueObject/DILEval.h"
@@ -42,6 +44,83 @@ DILDiagnosticError::DILDiagnosticError(llvm::StringRef expr,
m_detail.rendered = std::move(rendered_msg);
}
+llvm::Expected<lldb::TypeSystemSP>
+DILGetTypeSystemFromCU(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);
+}
+
+CompilerType
+ResolveTypeByName(const std::string &name,
+ std::shared_ptr<ExecutionContextScope> ctx_scope) {
+ // Internally types don't have global scope qualifier in their names and
+ // LLDB doesn't support queries with it too.
+ llvm::StringRef name_ref(name);
+
+ if (name_ref.starts_with("::"))
+ name_ref = name_ref.drop_front(2);
+
+ std::vector<CompilerType> result_type_list;
+ lldb::TargetSP target_sp = ctx_scope->CalculateTarget();
+ const char *type_name = name_ref.data();
+ if (type_name && type_name[0] && target_sp) {
+ ModuleList &images = target_sp->GetImages();
+ ConstString const_type_name(type_name);
+ TypeQuery query(type_name);
+ TypeResults results;
+ images.FindTypes(nullptr, query, results);
+ for (const lldb::TypeSP &type_sp : results.GetTypeMap().Types())
+ if (type_sp)
+ result_type_list.push_back(type_sp->GetFullCompilerType());
+
+ if (auto process_sp = target_sp->GetProcessSP()) {
+ for (auto *runtime : process_sp->GetLanguageRuntimes()) {
+ if (auto *vendor = runtime->GetDeclVendor()) {
+ auto types = vendor->FindTypes(const_type_name, UINT32_MAX);
+ for (auto type : types)
+ result_type_list.push_back(type);
+ }
+ }
+ }
+
+ if (result_type_list.empty()) {
+ for (auto type_system_sp : target_sp->GetScratchTypeSystems())
+ if (auto compiler_type =
+ type_system_sp->GetBuiltinTypeByName(const_type_name))
+ result_type_list.push_back(compiler_type);
+ }
+ }
+
+ // We've found multiple types, try finding the "correct" one.
+ CompilerType full_match;
+ std::vector<CompilerType> partial_matches;
+
+ for (uint32_t i = 0; i < result_type_list.size(); ++i) {
+ CompilerType type = result_type_list[i];
+ llvm::StringRef type_name_ref = type.GetTypeName().GetStringRef();
+ ;
+
+ if (type_name_ref == name_ref)
+ full_match = type;
+ else if (type_name_ref.ends_with(name_ref))
+ partial_matches.push_back(type);
+ }
+
+ // Full match is always correct.
+ if (full_match.IsValid())
+ return full_match;
+
+ // If we have partial matches, pick a "random" one.
+ if (partial_matches.size() > 0)
+ return partial_matches.back();
+
+ return {};
+}
+
llvm::Expected<ASTNodeUP>
DILParser::Parse(llvm::StringRef dil_input_expr, DILLexer lexer,
std::shared_ptr<StackFrame> frame_sp,
@@ -80,15 +159,64 @@ ASTNodeUP DILParser::Run() {
// Parse an expression.
//
// expression:
-// unary_expression
+// cast_expression
+//
+ASTNodeUP DILParser::ParseExpression() { return ParseCastExpression(); }
+
+// Parse a cast_expression.
//
-ASTNodeUP DILParser::ParseExpression() { return ParseUnaryExpression(); }
+// cast_expression:
+// unary_expression
+// "(" type_id ")" cast_expression
+
+ASTNodeUP DILParser::ParseCastExpression() {
+ // This can be a C-style cast, try parsing the contents as a type declaration.
+ if (CurToken().Is(Token::l_paren)) {
+ Token token = CurToken();
+ uint32_t loc = token.GetLocation();
+
+ // Enable lexer backtracking, so that we can rollback in case it's not
+ // actually a type declaration.
+
+ // Start tentative parsing (save token location/idx, for possible rollback).
+ uint32_t save_token_idx = m_dil_lexer.GetCurrentTokenIdx();
+
+ // Consume the token only after enabling the backtracking.
+ m_dil_lexer.Advance();
+
+ // Try parsing the type declaration. If the returned value is not valid,
+ // then we should rollback and try parsing the expression.
+ auto type_id = ParseTypeId();
+ if (type_id) {
+ // Successfully parsed the type declaration. Commit the backtracked
+ // tokens and parse the cast_expression.
+
+ if (!type_id.value().IsValid())
+ return std::make_unique<ErrorNode>();
+
+ Expect(Token::r_paren);
+ m_dil_lexer.Advance();
+ auto rhs = ParseCastExpression();
+
+ // return BuildCStyleCast(type_id.value(), std::move(rhs),
+ // token.GetLocation());
+ return std::make_unique<CStyleCastNode>(
+ loc, type_id.value(), std::move(rhs), CStyleCastKind::eNone);
+ }
+
+ // Failed to parse the contents of the parentheses as a type declaration.
+ // Rollback the lexer and try parsing it as unary_expression.
+ TentativeParsingRollback(save_token_idx);
+ }
+
+ return ParseUnaryExpression();
+}
// Parse an unary_expression.
//
// unary_expression:
// postfix_expression
-// unary_operator expression
+// unary_operator cast_expression
//
// unary_operator:
// "&"
@@ -99,7 +227,7 @@ ASTNodeUP DILParser::ParseUnaryExpression() {
Token token = CurToken();
uint32_t loc = token.GetLocation();
m_dil_lexer.Advance();
- auto rhs = ParseExpression();
+ auto rhs = ParseCastExpression();
switch (token.GetKind()) {
case Token::star:
return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::Deref,
@@ -271,6 +399,236 @@ std::string DILParser::ParseNestedNameSpecifier() {
}
}
+// Parse a type_id.
+//
+// type_id:
+// type_specifier_seq [abstract_declarator]
+std::optional<CompilerType> DILParser::ParseTypeId(bool must_be_type_id) {
+ uint32_t type_loc = CurToken().GetLocation();
+ TypeDeclaration type_decl;
+
+ // type_specifier_seq is required here, start with trying to parse it.
+ ParseTypeSpecifierSeq(&type_decl);
+
+ if (type_decl.IsEmpty()) {
+ // TODO: Should we bail out if `must_be_type_id` is set?
+ return {};
+ }
+
+ if (type_decl.m_has_error) {
+ if (type_decl.m_is_builtin) {
+ return {};
+ }
+
+ assert(type_decl.m_is_user_type && "type_decl must be a user type");
+ // Found something looking like a user type, but failed to parse it.
+ // Return invalid type if we expect to have a type here, otherwise nullopt.
+ if (must_be_type_id) {
+ return {};
+ }
+ return {};
+ }
+
+ // Try to resolve the base type.
+ CompilerType type;
+ if (type_decl.m_is_builtin) {
+ llvm::Expected<lldb::TypeSystemSP> type_system =
+ DILGetTypeSystemFromCU(m_ctx_scope);
+ if (!type_system)
+ return {};
+ // type = GetBasicType(m_ctx_scope, type_decl.GetBasicType());
+ // type = DILGetBasicType(*type_system, type_decl.GetBasicType());
+ type = (*type_system).get()->GetBasicTypeFromAST(type_decl.GetBasicType());
+ assert(type.IsValid() && "cannot resolve basic type");
+
+ } else {
+ assert(type_decl.m_is_user_type && "type_decl must be a user type");
+ type = ResolveTypeByName(type_decl.m_user_typename, m_ctx_scope);
+ if (!type.IsValid()) {
+ if (must_be_type_id) {
+ BailOut(
+ llvm::formatv("unknown type name '{0}'", type_decl.m_user_typename),
+ type_loc, CurToken().GetSpelling().length());
+ return {};
+ }
+ return {};
+ }
+
+ if (LookupIdentifier(type_decl.m_user_typename, m_ctx_scope,
+ m_use_dynamic)) {
+ // Same-name identifiers should be preferred over typenames.
+ // TODO: Make type accessible with 'class', 'struct' and 'union' keywords.
+ if (must_be_type_id) {
+ BailOut(llvm::formatv(
+ "must use '{0}' tag to refer to type '{1}' in this scope",
+ type.GetTypeTag(), type_decl.m_user_typename),
+ type_loc, CurToken().GetSpelling().length());
+ return {};
+ }
+ return {};
+ }
+
+ if (LookupGlobalIdentifier(type_decl.m_user_typename, m_ctx_scope,
+ m_ctx_scope->CalculateTarget(), m_use_dynamic)) {
+ // Same-name identifiers should be preferred over typenames.
+ // TODO: Make type accessible with 'class', 'struct' and 'union' keywords.
+ if (must_be_type_id) {
+ BailOut(llvm::formatv(
+ "must use '{0}' tag to refer to type '{1}' in this scope",
+ type.GetTypeTag(), type_decl.m_user_typename),
+ type_loc, CurToken().GetSpelling().length());
+ return {};
+ }
+ return {};
+ }
+ }
+
+ //
+ // abstract_declarator:
+ // ptr_operator [abstract_declarator]
+ //
+ std::vector<Token> ptr_operators;
+ while (CurToken().IsOneOf({Token::star, Token::amp})) {
+ Token tok = CurToken();
+ ptr_operators.push_back(std::move(tok));
+ m_dil_lexer.Advance();
+ }
+ type = ResolveTypeDeclarators(type, ptr_operators);
+
+ return type;
+}
+
+// Parse a type_specifier_seq.
+//
+// type_specifier_seq:
+// type_specifier [type_specifier_seq]
+//
+void DILParser::ParseTypeSpecifierSeq(TypeDeclaration *type_decl) {
+ while (true) {
+ bool type_specifier = ParseTypeSpecifier(type_decl);
+ if (!type_specifier) {
+ break;
+ }
+ }
+}
+
+// Parse a type_specifier.
+//
+// type_specifier:
+// simple_type_specifier
+// cv_qualifier
+//
+// simple_type_specifier:
+// ["::"] [nested_name_specifier] type_name
+// "char"
+// "bool"
+// "integer"
+// "float"
+// "void"
+//
+// Returns TRUE if a type_specifier was successfully parsed at this location.
+//
+bool DILParser::ParseTypeSpecifier(TypeDeclaration *type_decl) {
+ if (IsSimpleTypeSpecifierKeyword(CurToken())) {
+ // User-defined typenames can't be combined with builtin keywords.
+ if (type_decl->m_is_user_type) {
+ BailOut("cannot combine with previous declaration specifier",
+ CurToken().GetLocation(), CurToken().GetSpelling().length());
+ type_decl->m_has_error = true;
+ return false;
+ }
+
+ // From now on this type declaration must describe a builtin type.
+ // TODO: Should this be allowed -- `unsigned myint`?
+ type_decl->m_is_builtin = true;
+
+ if (!HandleSimpleTypeSpecifier(type_decl)) {
+ type_decl->m_has_error = true;
+ return false;
+ }
+ m_dil_lexer.Advance();
+ return true;
+ }
+
+ // The type_specifier must be a user-defined type. Try parsing a
+ // simple_type_specifier.
+ {
+ // Try parsing optional global scope operator.
+ bool global_scope = false;
+ if (CurToken().Is(Token::coloncolon)) {
+ global_scope = true;
+ m_dil_lexer.Advance();
+ }
+
+ uint32_t loc = CurToken().GetLocation();
+
+ // Try parsing optional nested_name_specifier.
+ auto nested_name_specifier = ParseNestedNameSpecifier();
+
+ // Try parsing required type_name.
+ auto type_name = ParseTypeName();
+
+ // If there is a type_name, then this is indeed a simple_type_specifier.
+ // Global and qualified (namespace/class) scopes can be empty, since they're
+ // optional. In this case type_name is type we're looking for.
+ if (!type_name.empty()) {
+ // User-defined typenames can't be combined with builtin keywords.
+ if (type_decl->m_is_builtin) {
+ BailOut("cannot combine with previous declaration specifier", loc,
+ CurToken().GetSpelling().length());
+ type_decl->m_has_error = true;
+ return false;
+ }
+ // There should be only one user-defined typename.
+ if (type_decl->m_is_user_type) {
+ BailOut("two or more data types in declaration of 'type name'", loc,
+ CurToken().GetSpelling().length());
+ type_decl->m_has_error = true;
+ return false;
+ }
+
+ // Construct the fully qualified typename.
+ type_decl->m_is_user_type = true;
+ type_decl->m_user_typename =
+ llvm::formatv("{0}{1}{2}", global_scope ? "::" : "",
+ nested_name_specifier, type_name);
+ return true;
+ }
+ }
+
+ // No type_specifier was found here.
+ return false;
+}
+
+// Parse a type_name.
+//
+// type_name:
+// class_name
+// enum_name
+// typedef_name
+//
+// class_name
+// identifier
+//
+// enum_name
+// identifier
+//
+// typedef_name
+// identifier
+//
+std::string DILParser::ParseTypeName() {
+ // Typename always starts with an identifier.
+ if (CurToken().IsNot(Token::identifier)) {
+ return "";
+ }
+
+ // Otherwise look for a class_name, enum_name or a typedef_name.
+ std::string identifier = CurToken().GetSpelling();
+ m_dil_lexer.Advance();
+
+ return identifier;
+}
+
// Parse an id_expression.
//
// id_expression:
@@ -336,6 +694,204 @@ std::string DILParser::ParseUnqualifiedId() {
return identifier;
}
+CompilerType
+DILParser::ResolveTypeDeclarators(CompilerType type,
+ const std::vector<Token> &ptr_operators) {
+ CompilerType bad_type;
+ // Resolve pointers/references.
+ for (Token tk : ptr_operators) {
+ uint32_t loc = tk.GetLocation();
+ if (tk.GetKind() == Token::star) {
+ // Pointers to reference types are forbidden.
+ if (type.IsReferenceType()) {
+ BailOut(llvm::formatv("'type name' declared as a pointer to a "
+ "reference of type {0}",
+ type.TypeDescription()),
+ loc, CurToken().GetSpelling().length());
+ return bad_type;
+ }
+ // Get pointer type for the base type: e.g. int* -> int**.
+ type = type.GetPointerType();
+
+ } else if (tk.GetKind() == Token::amp) {
+ // References to references are forbidden.
+ if (type.IsReferenceType()) {
+ BailOut("type name declared as a reference to a reference", loc,
+ CurToken().GetSpelling().length());
+ return bad_type;
+ }
+ // Get reference type for the base type: e.g. int -> int&.
+ type = type.GetLValueReferenceType();
+ }
+ }
+
+ return type;
+}
+
+bool DILParser::IsSimpleTypeSpecifierKeyword(Token token) const {
+ if (token.GetKind() != Token::identifier)
+ return false;
+ if (token.GetSpelling() == "bool" || token.GetSpelling() == "char" ||
+ token.GetSpelling() == "int" || token.GetSpelling() == "float" ||
+ token.GetSpelling() == "void" || token.GetSpelling() == "short" ||
+ token.GetSpelling() == "long" || token.GetSpelling() == "signed" ||
+ token.GetSpelling() == "unsigned" || token.GetSpelling() == "double")
+ return true;
+ return false;
+}
+
+bool DILParser::HandleSimpleTypeSpecifier(TypeDeclaration *type_decl) {
+ using TypeSpecifier = TypeDeclaration::TypeSpecifier;
+ using SignSpecifier = TypeDeclaration::SignSpecifier;
+
+ TypeSpecifier type_spec = type_decl->m_type_specifier;
+ uint32_t loc = CurToken().GetLocation();
+ std::string kind = CurToken().GetSpelling();
+
+ // switch (kind) {
+ if (kind == "int") {
+ // case Token::kw_int: {
+ // "int" can have signedness and be combined with "short", "long" and
+ // "long long" (but not with another "int").
+ if (type_decl->m_has_int_specifier) {
+ BailOut("cannot combine with previous 'int' declaration specifier", loc,
+ CurToken().GetSpelling().length());
+ return false;
+ }
+ if (type_spec == TypeSpecifier::kShort ||
+ type_spec == TypeSpecifier::kLong ||
+ type_spec == TypeSpecifier::kLongLong) {
+ type_decl->m_has_int_specifier = true;
+ return true;
+ } else if (type_spec == TypeSpecifier::kUnknown) {
+ type_decl->m_type_specifier = TypeSpecifier::kInt;
+ type_decl->m_has_int_specifier = true;
+ return true;
+ }
+ BailOut(llvm::formatv(
+ "cannot combine with previous '{0}' declaration specifier",
+ type_spec),
+ loc, CurToken().GetSpelling().length());
+ return false;
+ }
+
+ if (kind == "long") {
+ // "long" can have signedness and be combined with "int" or "long" to
+ // form "long long".
+ if (type_spec == TypeSpecifier::kUnknown ||
+ type_spec == TypeSpecifier::kInt) {
+ type_decl->m_type_specifier = TypeSpecifier::kLong;
+ return true;
+ } else if (type_spec == TypeSpecifier::kLong) {
+ type_decl->m_type_specifier = TypeSpecifier::kLongLong;
+ return true;
+ } else if (type_spec == TypeSpecifier::kDouble) {
+ type_decl->m_type_specifier = TypeSpecifier::kLongDouble;
+ return true;
+ }
+ BailOut(llvm::formatv(
+ "cannot combine with previous '{0}' declaration specifier",
+ type_spec),
+ loc, CurToken().GetSpelling().length());
+ return false;
+ }
+
+ if (kind == "short") {
+ // "short" can have signedness and be combined with "int".
+ if (type_spec == TypeSpecifier::kUnknown ||
+ type_spec == TypeSpecifier::kInt) {
+ type_decl->m_type_specifier = TypeSpecifier::kShort;
+ return true;
+ }
+ BailOut(llvm::formatv(
+ "cannot combine with previous '{0}' declaration specifier",
+ type_spec),
+ loc, CurToken().GetSpelling().length());
+ return false;
+ }
+
+ if (kind == "char") {
+ // "char" can have signedness, but it cannot be combined with any other
+ // type specifier.
+ if (type_spec == TypeSpecifier::kUnknown) {
+ type_decl->m_type_specifier = TypeSpecifier::kChar;
+ return true;
+ }
+ BailOut(llvm::formatv(
+ "cannot combine with previous '{0}' declaration specifier",
+ type_spec),
+ loc, CurToken().GetSpelling().length());
+ return false;
+ }
+
+ if (kind == "double") {
+ // "double" can be combined with "long" to form "long double", but it
+ // cannot be combined with signedness specifier.
+ if (type_decl->m_sign_specifier != SignSpecifier::kUnknown) {
+ BailOut("'double' cannot be signed or unsigned", loc,
+ CurToken().GetSpelling().length());
+ return false;
+ }
+ if (type_spec == TypeSpecifier::kUnknown) {
+ type_decl->m_type_specifier = TypeSpecifier::kDouble;
+ return true;
+ } else if (type_spec == TypeSpecifier::kLong) {
+ type_decl->m_type_specifier = TypeSpecifier::kLongDouble;
+ return true;
+ }
+ BailOut(llvm::formatv(
+ "cannot combine with previous '{0}' declaration specifier",
+ type_spec),
+ loc, CurToken().GetSpelling().length());
+ return false;
+ }
+
+ if (kind == "bool" || kind == "void" || kind == "float") {
+ // These types cannot have signedness or be combined with any other type
+ // specifiers.
+ if (type_decl->m_sign_specifier != SignSpecifier::kUnknown) {
+ BailOut(llvm::formatv("'{0}' cannot be signed or unsigned", kind), loc,
+ CurToken().GetSpelling().length());
+ return false;
+ }
+ if (type_spec != TypeSpecifier::kUnknown) {
+ BailOut(llvm::formatv(
+ "cannot combine with previous '{0}' declaration specifier",
+ type_spec),
+ loc, CurToken().GetSpelling().length());
+ }
+ if (kind == "bool")
+ type_decl->m_type_specifier = TypeSpecifier::kBool;
+ else if (kind == "void")
+ type_decl->m_type_specifier = TypeSpecifier::kVoid;
+ else if (kind == "float")
+ type_decl->m_type_specifier = TypeSpecifier::kFloat;
+ return true;
+ }
+
+ if (kind == "signed" || kind == "unsigned") {
+ // "signed" and "unsigned" cannot be combined with another signedness
+ // specifier.
+ if (type_spec == TypeSpecifier::kVoid ||
+ type_spec == TypeSpecifier::kBool ||
+ type_spec == TypeSpecifier::kFloat ||
+ type_spec == TypeSpecifier::kDouble ||
+ type_spec == TypeSpecifier::kLongDouble) {
+ BailOut(llvm::formatv("'{0}' cannot be signed or unsigned", type_spec),
+ loc, CurToken().GetSpelling().length());
+ return false;
+ }
+
+ type_decl->m_sign_specifier =
+ (kind == "signed") ? SignSpecifier::kSigned : SignSpecifier::kUnsigned;
+ return true;
+ }
+
+ BailOut(llvm::formatv("invalid simple type specifier kind"), loc,
+ CurToken().GetSpelling().length());
+ return false;
+}
+
void DILParser::BailOut(const std::string &error, uint32_t loc,
uint16_t err_len) {
if (m_error)
@@ -444,4 +1000,74 @@ void DILParser::Expect(Token::Kind kind) {
}
}
+void DILParser::ExpectOneOf(std::vector<Token::Kind> kinds_vec) {
+ if (!CurToken().IsOneOf(kinds_vec)) {
+ BailOut(llvm::formatv("expected any of ({0}), got: {1}",
+ llvm::iterator_range(kinds_vec), CurToken()),
+ CurToken().GetLocation(), CurToken().GetSpelling().length());
+ }
+}
+
+lldb::BasicType TypeDeclaration::GetBasicType() const {
+ if (!m_is_builtin)
+ return lldb::eBasicTypeInvalid;
+
+ if (m_sign_specifier == SignSpecifier::kSigned &&
+ m_type_specifier == TypeSpecifier::kChar) {
+ // "signed char" isn't the same as "char".
+ return lldb::eBasicTypeSignedChar;
+ }
+
+ if (m_sign_specifier == SignSpecifier::kUnsigned) {
+ switch (m_type_specifier) {
+ // "unsigned" is "unsigned int"
+ case TypeSpecifier::kUnknown:
+ return lldb::eBasicTypeUnsignedInt;
+ case TypeSpecifier::kChar:
+ return lldb::eBasicTypeUnsignedChar;
+ case TypeSpecifier::kShort:
+ return lldb::eBasicTypeUnsignedShort;
+ case TypeSpecifier::kInt:
+ return lldb::eBasicTypeUnsignedInt;
+ case TypeSpecifier::kLong:
+ return lldb::eBasicTypeUnsignedLong;
+ case TypeSpecifier::kLongLong:
+ return lldb::eBasicTypeUnsignedLongLong;
+ default:
+ // assert(false && "unknown unsigned basic type");
+ return lldb::eBasicTypeInvalid;
+ }
+ }
+
+ switch (m_type_specifier) {
+ case TypeSpecifier::kUnknown:
+ // "signed" is "signed int"
+ if (m_sign_specifier != SignSpecifier::kSigned)
+ return lldb::eBasicTypeInvalid;
+ return lldb::eBasicTypeInt;
+ case TypeSpecifier::kVoid:
+ return lldb::eBasicTypeVoid;
+ case TypeSpecifier::kBool:
+ return lldb::eBasicTypeBool;
+ case TypeSpecifier::kChar:
+ return lldb::eBasicTypeChar;
+ case TypeSpecifier::kShort:
+ return lldb::eBasicTypeShort;
+ case TypeSpecifier::kInt:
+ return lldb::eBasicTypeInt;
+ case TypeSpecifier::kLong:
+ return lldb::eBasicTypeLong;
+ case TypeSpecifier::kLongLong:
+ return lldb::eBasicTypeLongLong;
+ case TypeSpecifier::kFloat:
+ return lldb::eBasicTypeFloat;
+ case TypeSpecifier::kDouble:
+ return lldb::eBasicTypeDouble;
+ case TypeSpecifier::kLongDouble:
+ return lldb::eBasicTypeLongDouble;
+ }
+
+ return lldb::eBasicTypeInvalid;
+}
+
} // namespace lldb_private::dil
diff --git a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
index 0f6618fe47984..85899caaa7433 100644
--- a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
+++ b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
@@ -28,4 +28,5 @@ def test_frame_var(self):
self.expect_var_path("a", value="1")
self.expect_var_path("b", value="2")
self.expect_var_path("c", value="'\\xfd'")
+ self.expect_var_path("(int)c", value="-3")
self.expect_var_path("s", value="4")
diff --git a/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/Makefile b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/Makefile
new file mode 100644
index 0000000000000..0165eb73f3073
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/Makefile
@@ -0,0 +1,6 @@
+CXX_SOURCES := main.cpp
+#CXXFLAGS_EXTRAS := -std=c++14
+
+USE_LIBSTDCPP := 1
+
+include Makefile.rules
diff --git a/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py
new file mode 100644
index 0000000000000..001e39d8a9137
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py
@@ -0,0 +1,233 @@
+"""
+Make sure 'frame var' using DIL parser/evaultor works for C-Style casts.
+"""
+
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test import lldbutil
+
+import os
+import shutil
+import time
+
+class TestFrameVarDILCStyleCast(TestBase):
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def expect_var_path(self, expr, compare_to_framevar=False, value=None, type=None):
+ value_dil = super().expect_var_path(expr, value=value, type=type)
+ if compare_to_framevar:
+ self.runCmd("settings set target.experimental.use-DIL false")
+ value_frv = super().expect_var_path(expr, value=value, type=type)
+ self.runCmd("settings set target.experimental.use-DIL true")
+ self.assertEqual(value_dil.GetValue(), value_frv.GetValue())
+
+ def test_type_cast(self):
+ self.build()
+ (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+ self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
+ )
+
+ self.runCmd("settings set target.experimental.use-DIL true")
+
+ # TestCStyleCastBUiltins
+
+ self.expect_var_path("(int)1", value="1", type="int")
+ self.expect_var_path("(long long)1", value="1", type="long long")
+ self.expect_var_path("(unsigned long)1", value="1", type="unsigned long")
+ self.expect_var_path("(char*)1", value="0x0000000000000001", type="char *")
+ self.expect_var_path("(long long**)1", value="0x0000000000000001", type="long long **")
+
+ self.expect("frame variable '(long&*)1'", error=True,
+ substrs=["'type name' declared as a pointer to a reference"
+ " of type 'long &'"])
+
+ self.expect("frame variable '(long& &)1'", error=True,
+ substrs=["type name declared as a reference to a reference"])
+
+ self.expect("frame variable '(long 1)1'", error=True,
+ substrs=["expected 'r_paren', got: <'1' "
+ "(integer_constant)>"])
+
+ # TestCStyleCastBasicType
+
+ # Test with integer literals.
+ self.expect_var_path("(char)1", type="char", value="'\\x01'")
+ self.expect_var_path("(long long)1", type="long long", value="1")
+ self.expect_var_path("(short)65534", type="short", value="-2")
+ self.expect_var_path("(unsigned short)100000",
+ type="unsigned short", value="34464")
+ self.expect_var_path("(float)1", type="float", value="1")
+ self.expect_var_path("(float)1.1", type="float", value="1.10000002")
+ self.expect_var_path("(float)1.1f", type="float", value="1.10000002")
+ self.expect_var_path("(double)1", type="double", value="1")
+ self.expect_var_path("(double)1.1",
+ type="double", value="1.1000000000000001")
+ self.expect_var_path("(double)1.1f",
+ type="double", value="1.1000000238418579")
+ self.expect_var_path("(int)1.1", type="int", value="1")
+ self.expect_var_path("(int)1.1f", type="int", value="1")
+ self.expect_var_path("(long)1.1", type="long", value="1")
+ self.expect_var_path("(bool)0", type="bool", value="false")
+ self.expect_var_path("(bool)0.0", type="bool", value="false")
+ self.expect_var_path("(bool)0.0f", type="bool", value="false")
+ self.expect_var_path("(bool)3", type="bool", value="true")
+
+ self.expect("frame variable '&(int)1'", error=True,
+ substrs=["'result' doesn't have a valid address"])
+
+ # Test with variables.
+ self.expect_var_path("(char)a", type="char", value="'\\x01'")
+ self.expect_var_path("(unsigned char)na", type="unsigned char", value="'\\xff'")
+ self.expect_var_path("(short)na", type="short", value="-1")
+ self.expect_var_path("(long long)a", type="long long", value="1")
+ self.expect_var_path("(float)a", type="float", value="1")
+ self.expect_var_path("(float)f", type="float", value="1.10000002")
+ self.expect_var_path("(double)f",
+ type="double", value="1.1000000238418579")
+ self.expect_var_path("(int)f", type="int", value="1")
+ self.expect_var_path("(long)f", type="long", value="1")
+ self.expect_var_path("(bool)finf", type="bool", value="true")
+ self.expect_var_path("(bool)fnan", type="bool", value="true")
+ self.expect_var_path("(bool)fsnan", type="bool", value="true")
+ self.expect_var_path("(bool)fmax", type="bool", value="true")
+ self.expect_var_path("(bool)fdenorm", type="bool", value="true")
+ self.expect("frame variable '(int)ns_foo_'", error=True,
+ substrs=["cannot convert 'ns::Foo' to 'int' without a "
+ "conversion operator"])
+
+ # Test with typedefs and namespaces.
+ self.expect_var_path("(myint)1", type="myint", value="1")
+ self.expect_var_path("(myint)1LL", type="myint", value="1")
+ self.expect_var_path("(ns::myint)1", type="ns::myint", value="1")
+ self.expect_var_path("(::ns::myint)1", type="ns::myint", value="1")
+ self.expect_var_path("(::ns::myint)myint_", type="ns::myint", value="1")
+
+ self.expect_var_path("(int)myint_", type="int", value="1")
+ self.expect_var_path("(int)ns_myint_", type="int", value="2")
+ self.expect_var_path("(long long)myint_", type="long long", value="1")
+ self.expect_var_path("(long long)ns_myint_", type="long long", value="2")
+ self.expect_var_path("(::ns::myint)myint_", type="ns::myint", value="1")
+
+ self.expect_var_path("(ns::inner::mydouble)1", type="ns::inner::mydouble", value="1")
+ self.expect_var_path("(::ns::inner::mydouble)1.2",
+ type="ns::inner::mydouble", value="1.2")
+ self.expect_var_path("(ns::inner::mydouble)myint_",
+ type="ns::inner::mydouble", value="1")
+ self.expect_var_path("(::ns::inner::mydouble)ns_inner_mydouble_",
+ type="ns::inner::mydouble", value="1.2")
+ self.expect_var_path("(myint)ns_inner_mydouble_",
+ type="myint", value="1")
+
+ # Test with pointers and arrays.
+ self.expect_var_path("(long long)ap", type="long long")
+ self.expect_var_path("(unsigned long long)vp", type="unsigned long long")
+ self.expect_var_path("(long long)arr", type="long long")
+ self.expect_var_path("(bool)ap", type="bool", value="true")
+ self.expect_var_path("(bool)(int*)0x00000000",
+ type="bool", value="false")
+ self.expect_var_path("(bool)arr", type="bool", value="true")
+ self.expect("frame variable '(char)ap'", error=True,
+ substrs=["cast from pointer to smaller type 'char' loses "
+ "information"])
+ Is32Bit = False
+ if self.target().GetAddressByteSize() == 4:
+ Is32Bit = True;
+
+ if Is32Bit:
+ self.expect("frame variable '(int)arr'", error=True,
+ substrs=["cast from pointer to smaller type 'int' loses"
+ " information"])
+ else:
+ self.expect("frame variable '(int)arr'", error=True,
+ substrs=["cast from pointer to smaller type 'int' loses"
+ " information"])
+
+ self.expect("frame variable '(float)ap'", error=True,
+ substrs=["C-style cast from 'int *' to 'float' is not "
+ "allowed"])
+ self.expect("frame variable '(float)arr'", error=True,
+ substrs=["C-style cast from 'int *' to 'float' is not "
+ "allowed"])
+
+ # TestCStyleCastPointer
+ self.expect_var_path("(void*)&a", type="void *")
+ self.expect_var_path("(void*)ap", type="void *")
+ self.expect_var_path("(long long*)vp", type="long long *")
+ self.expect_var_path("(short int*)vp", type="short *")
+ self.expect_var_path("(unsigned long long*)vp", type="unsigned long long *")
+ self.expect_var_path("(unsigned short int*)vp", type="unsigned short *")
+
+
+ if Is32Bit:
+ self.expect_var_path("(void*)0",
+ type="void *", value="0x00000000")
+ self.expect_var_path("(void*)1",
+ type="void *", value="0x00000001")
+ self.expect_var_path("(void*)a",
+ type="void *", value="0x00000001")
+ self.expect_var_path("(void*)na",
+ type="void *", value="0xffffffff")
+ else:
+ self.expect_var_path("(void*)0",
+ type="void *", value="0x0000000000000000")
+ self.expect_var_path("(void*)1",
+ type="void *", value="0x0000000000000001")
+ self.expect_var_path("(void*)a",
+ type="void *", value="0x0000000000000001")
+ self.expect_var_path("(void*)na",
+ type="void *", value="0xffffffffffffffff")
+
+ self.expect_var_path("(int*&)ap", type="int *")
+
+ self.expect("frame variable '(char*) 1.0'", error=True,
+ substrs=["cannot cast from type 'double' to pointer type"
+ " 'char *'"])
+
+ self.expect_var_path("*(int*)(void*)ap", type="int", value="1")
+
+ self.expect_var_path("(ns::Foo*)ns_inner_foo_ptr_", type="ns::Foo *")
+ self.expect_var_path("(ns::inner::Foo*)ns_foo_ptr_", type="ns::inner::Foo *")
+
+ self.expect("frame variable '(int& &)ap'", error=True,
+ substrs=["type name declared as a reference to a "
+ "reference"])
+ self.expect("frame variable '(int&*)ap'", error=True,
+ substrs=["'type name' declared as a pointer "
+ "to a reference of type 'int &'"])
+
+ if Is32Bit:
+ self.expect_var_path("(void *)0", type="void *", value="0x00000000")
+ else:
+ self.expect_var_path("(void *)0", type="void *", value="0x0000000000000000")
+
+
+ # TestCStyleCastArray
+
+ threads = lldbutil.continue_to_source_breakpoint(
+ self, process,"Set a breakpoint here", lldb.SBFileSpec("main.cpp")
+ )
+ self.assertEqual(
+ len(threads), 1, "There should be a thread stopped at our breakpoint"
+ )
+
+ self.expect_var_path("(int*)arr_1d", type="int *")
+ self.expect_var_path("(char*)arr_1d", type="char *")
+ self.expect_var_path("((char*)arr_1d)[0]", type="char", value="'\\x01'")
+ self.expect_var_path("((char*)arr_1d)[1]", type="char", value="'\\0'")
+
+ # 2D arrays.
+ self.expect_var_path("(int*)arr_2d", type="int *")
+ self.expect_var_path("((int*)arr_2d)[1]", type="int", value="2")
+ self.expect_var_path("((int*)arr_2d)[2]", type="int", value="3")
+ self.expect_var_path("((int*)arr_2d[1])[1]", type="int", value="5")
+
+ # TestCStyleCastReference
+
+ self.expect_var_path("((InnerFoo&)arr_1d[1]).a", type="int", value="2")
+ self.expect_var_path("((InnerFoo&)arr_1d[1]).b", type="int", value="3")
+
+ self.expect_var_path("(int&)arr_1d[0]", type="int", value="1")
+ self.expect_var_path("(int&)arr_1d[1]", type="int", value="2")
+
+ self.expect_var_path("&(int&)arr_1d", type="int *")
diff --git a/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/main.cpp b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/main.cpp
new file mode 100644
index 0000000000000..0fd841d95cdf6
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/main.cpp
@@ -0,0 +1,81 @@
+// CStyleCast, main.cpp
+
+#include <cstdarg>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <limits>
+#include <memory>
+#include <string>
+
+namespace ns {
+
+typedef int myint;
+
+class Foo {};
+
+namespace inner {
+
+using mydouble = double;
+
+class Foo {};
+
+} // namespace inner
+
+} // namespace ns
+
+int main(int argc, char **argv) {
+ int a = 1;
+ int *ap = &a;
+ void *vp = &a;
+ int arr[2] = {1, 2};
+
+ int na = -1;
+ float f = 1.1;
+
+ typedef int myint;
+ std::nullptr_t std_nullptr_t = nullptr;
+ bool found_it = false;
+ if (std_nullptr_t) {
+ found_it = true;
+ } else {
+ found_it = (bool)0;
+ }
+
+ myint myint_ = 1;
+ ns::myint ns_myint_ = 2;
+ ns::Foo ns_foo_;
+ ns::Foo *ns_foo_ptr_ = &ns_foo_;
+
+ ns::inner::mydouble ns_inner_mydouble_ = 1.2;
+ ns::inner::Foo ns_inner_foo_;
+ ns::inner::Foo *ns_inner_foo_ptr_ = &ns_inner_foo_;
+
+ float finf = std::numeric_limits<float>::infinity();
+ float fnan = std::numeric_limits<float>::quiet_NaN();
+ float fsnan = std::numeric_limits<float>::signaling_NaN();
+ float fmax = std::numeric_limits<float>::max();
+ float fdenorm = std::numeric_limits<float>::denorm_min();
+
+ // TestCStyleCastBuiltins
+ // TestCStyleCastBasicType
+ // TestCStyleCastPointer
+ // TestCStyleCastNullptrType
+ if (false) { // Set a breakpoint here
+ }
+
+ struct InnerFoo {
+ int a;
+ int b;
+ };
+
+ InnerFoo ifoo;
+ (void)ifoo;
+
+ int arr_1d[] = {1, 2, 3, 4};
+ int arr_2d[2][3] = {{1, 2, 3}, {4, 5, 6}};
+
+ // TestCStyleCastArray
+ // TestCStyleCastReference
+ return 0; // Set a breakpoint here
+}
>From 16466702cd29a17abf1cd30f6536a31678809f6b Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Tue, 23 Sep 2025 21:20:10 -0700
Subject: [PATCH 2/7] Address review comments in cast test & fix clang-format
issues.
---
lldb/include/lldb/ValueObject/DILEval.h | 2 -
lldb/source/ValueObject/DILParser.cpp | 2 -
.../LocalVars/TestFrameVarDILLocalVars.py | 1 +
.../CStyleCast/TestFrameVarDILCStyleCast.py | 205 ++++++++++--------
.../frame/var-dil/expr/CStyleCast/main.cpp | 9 -
5 files changed, 113 insertions(+), 106 deletions(-)
diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h
index adaad1a705a5a..0563436b93aa3 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -63,8 +63,6 @@ class Interpreter : Visitor {
llvm::Expected<lldb::ValueObjectSP>
Visit(const CStyleCastNode *node) override;
-
-
llvm::Expected<CompilerType>
PickIntegerType(lldb::TypeSystemSP type_system,
std::shared_ptr<ExecutionContextScope> ctx,
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index fd7678ed73b7a..e4e40a5869831 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -697,7 +697,6 @@ std::string DILParser::ParseUnqualifiedId() {
return identifier;
}
-
CompilerType
DILParser::ResolveTypeDeclarators(CompilerType type,
const std::vector<Token> &ptr_operators) {
@@ -1026,7 +1025,6 @@ void DILParser::ExpectOneOf(std::vector<Token::Kind> kinds_vec) {
}
}
-
lldb::BasicType TypeDeclaration::GetBasicType() const {
if (!m_is_builtin)
return lldb::eBasicTypeInvalid;
diff --git a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
index 85899caaa7433..e142b654b00e6 100644
--- a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
+++ b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
@@ -12,6 +12,7 @@
import time
+
class TestFrameVarDILLocalVars(TestBase):
# If your test case doesn't stress debug info, then
# set this to true. That way it won't be run once for
diff --git a/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py
index 001e39d8a9137..6c2f0eb77ce0c 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py
+++ b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py
@@ -12,15 +12,6 @@
import time
class TestFrameVarDILCStyleCast(TestBase):
- NO_DEBUG_INFO_TESTCASE = True
-
- def expect_var_path(self, expr, compare_to_framevar=False, value=None, type=None):
- value_dil = super().expect_var_path(expr, value=value, type=type)
- if compare_to_framevar:
- self.runCmd("settings set target.experimental.use-DIL false")
- value_frv = super().expect_var_path(expr, value=value, type=type)
- self.runCmd("settings set target.experimental.use-DIL true")
- self.assertEqual(value_dil.GetValue(), value_frv.GetValue())
def test_type_cast(self):
self.build()
@@ -36,18 +27,29 @@ def test_type_cast(self):
self.expect_var_path("(long long)1", value="1", type="long long")
self.expect_var_path("(unsigned long)1", value="1", type="unsigned long")
self.expect_var_path("(char*)1", value="0x0000000000000001", type="char *")
- self.expect_var_path("(long long**)1", value="0x0000000000000001", type="long long **")
+ self.expect_var_path(
+ "(long long**)1", value="0x0000000000000001", type="long long **"
+ )
- self.expect("frame variable '(long&*)1'", error=True,
- substrs=["'type name' declared as a pointer to a reference"
- " of type 'long &'"])
+ self.expect(
+ "frame variable '(long&*)1'",
+ error=True,
+ substrs=[
+ "'type name' declared as a pointer to a reference of type 'long &'"
+ ],
+ )
- self.expect("frame variable '(long& &)1'", error=True,
- substrs=["type name declared as a reference to a reference"])
+ self.expect(
+ "frame variable '(long& &)1'",
+ error=True,
+ substrs=["type name declared as a reference to a reference"],
+ )
- self.expect("frame variable '(long 1)1'", error=True,
- substrs=["expected 'r_paren', got: <'1' "
- "(integer_constant)>"])
+ self.expect(
+ "frame variable '(long 1)1'",
+ error=True,
+ substrs=["expected 'r_paren', got: <'1' (integer_constant)>"],
+ )
# TestCStyleCastBasicType
@@ -55,16 +57,21 @@ def test_type_cast(self):
self.expect_var_path("(char)1", type="char", value="'\\x01'")
self.expect_var_path("(long long)1", type="long long", value="1")
self.expect_var_path("(short)65534", type="short", value="-2")
- self.expect_var_path("(unsigned short)100000",
- type="unsigned short", value="34464")
+ self.expect_var_path(
+ "(unsigned short)100000", type="unsigned short", value="34464"
+ )
+ self.expect_var_path("(int)false", type="int", value="0")
+ self.expect_var_path("(int)true", type="int", value="1")
self.expect_var_path("(float)1", type="float", value="1")
self.expect_var_path("(float)1.1", type="float", value="1.10000002")
self.expect_var_path("(float)1.1f", type="float", value="1.10000002")
+ self.expect_var_path("(float)false", type="float", value="0")
+ self.expect_var_path("(float)true", type="float", value="1")
self.expect_var_path("(double)1", type="double", value="1")
- self.expect_var_path("(double)1.1",
- type="double", value="1.1000000000000001")
- self.expect_var_path("(double)1.1f",
- type="double", value="1.1000000238418579")
+ self.expect_var_path("(double)1.1", type="double", value="1.1000000000000001")
+ self.expect_var_path("(double)1.1f", type="double", value="1.1000000238418579")
+ self.expect_var_path("(double)false", type="double", value="0")
+ self.expect_var_path("(double)true", type="double", value="1")
self.expect_var_path("(int)1.1", type="int", value="1")
self.expect_var_path("(int)1.1f", type="int", value="1")
self.expect_var_path("(long)1.1", type="long", value="1")
@@ -73,8 +80,11 @@ def test_type_cast(self):
self.expect_var_path("(bool)0.0f", type="bool", value="false")
self.expect_var_path("(bool)3", type="bool", value="true")
- self.expect("frame variable '&(int)1'", error=True,
- substrs=["'result' doesn't have a valid address"])
+ self.expect(
+ "frame variable '&(int)1'",
+ error=True,
+ substrs=["'result' doesn't have a valid address"],
+ )
# Test with variables.
self.expect_var_path("(char)a", type="char", value="'\\x01'")
@@ -83,8 +93,7 @@ def test_type_cast(self):
self.expect_var_path("(long long)a", type="long long", value="1")
self.expect_var_path("(float)a", type="float", value="1")
self.expect_var_path("(float)f", type="float", value="1.10000002")
- self.expect_var_path("(double)f",
- type="double", value="1.1000000238418579")
+ self.expect_var_path("(double)f", type="double", value="1.1000000238418579")
self.expect_var_path("(int)f", type="int", value="1")
self.expect_var_path("(long)f", type="long", value="1")
self.expect_var_path("(bool)finf", type="bool", value="true")
@@ -92,9 +101,13 @@ def test_type_cast(self):
self.expect_var_path("(bool)fsnan", type="bool", value="true")
self.expect_var_path("(bool)fmax", type="bool", value="true")
self.expect_var_path("(bool)fdenorm", type="bool", value="true")
- self.expect("frame variable '(int)ns_foo_'", error=True,
- substrs=["cannot convert 'ns::Foo' to 'int' without a "
- "conversion operator"])
+ self.expect(
+ "frame variable '(int)ns_foo_'",
+ error=True,
+ substrs=[
+ "cannot convert 'ns::Foo' to 'int' without a conversion operator"
+ ],
+ )
# Test with typedefs and namespaces.
self.expect_var_path("(myint)1", type="myint", value="1")
@@ -109,46 +122,59 @@ def test_type_cast(self):
self.expect_var_path("(long long)ns_myint_", type="long long", value="2")
self.expect_var_path("(::ns::myint)myint_", type="ns::myint", value="1")
- self.expect_var_path("(ns::inner::mydouble)1", type="ns::inner::mydouble", value="1")
- self.expect_var_path("(::ns::inner::mydouble)1.2",
- type="ns::inner::mydouble", value="1.2")
- self.expect_var_path("(ns::inner::mydouble)myint_",
- type="ns::inner::mydouble", value="1")
- self.expect_var_path("(::ns::inner::mydouble)ns_inner_mydouble_",
- type="ns::inner::mydouble", value="1.2")
- self.expect_var_path("(myint)ns_inner_mydouble_",
- type="myint", value="1")
+ self.expect_var_path(
+ "(ns::inner::mydouble)1", type="ns::inner::mydouble", value="1"
+ )
+ self.expect_var_path(
+ "(::ns::inner::mydouble)1.2", type="ns::inner::mydouble", value="1.2"
+ )
+ self.expect_var_path(
+ "(ns::inner::mydouble)myint_", type="ns::inner::mydouble", value="1"
+ )
+ self.expect_var_path(
+ "(::ns::inner::mydouble)ns_inner_mydouble_",
+ type="ns::inner::mydouble",
+ value="1.2",
+ )
+ self.expect_var_path("(myint)ns_inner_mydouble_", type="myint", value="1")
# Test with pointers and arrays.
self.expect_var_path("(long long)ap", type="long long")
self.expect_var_path("(unsigned long long)vp", type="unsigned long long")
self.expect_var_path("(long long)arr", type="long long")
self.expect_var_path("(bool)ap", type="bool", value="true")
- self.expect_var_path("(bool)(int*)0x00000000",
- type="bool", value="false")
+ self.expect_var_path("(bool)(int*)0x00000000", type="bool", value="false")
self.expect_var_path("(bool)arr", type="bool", value="true")
- self.expect("frame variable '(char)ap'", error=True,
- substrs=["cast from pointer to smaller type 'char' loses "
- "information"])
+ self.expect(
+ "frame variable '(char)ap'",
+ error=True,
+ substrs=["cast from pointer to smaller type 'char' loses information"],
+ )
Is32Bit = False
if self.target().GetAddressByteSize() == 4:
- Is32Bit = True;
+ Is32Bit = True;
if Is32Bit:
- self.expect("frame variable '(int)arr'", error=True,
- substrs=["cast from pointer to smaller type 'int' loses"
- " information"])
+ self.expect("frame variable '(int)arr'", type="int")
else:
- self.expect("frame variable '(int)arr'", error=True,
- substrs=["cast from pointer to smaller type 'int' loses"
- " information"])
-
- self.expect("frame variable '(float)ap'", error=True,
- substrs=["C-style cast from 'int *' to 'float' is not "
- "allowed"])
- self.expect("frame variable '(float)arr'", error=True,
- substrs=["C-style cast from 'int *' to 'float' is not "
- "allowed"])
+ self.expect(
+ "frame variable '(int)arr'",
+ error=True,
+ substrs=[
+ "cast from pointer to smaller type 'int' loses information"
+ ],
+ )
+
+ self.expect(
+ "frame variable '(float)ap'",
+ error=True,
+ substrs=["C-style cast from 'int *' to 'float' is not allowed"],
+ )
+ self.expect(
+ "frame variable '(float)arr'",
+ error=True,
+ substrs=["C-style cast from 'int *' to 'float' is not allowed"],
+ )
# TestCStyleCastPointer
self.expect_var_path("(void*)&a", type="void *")
@@ -160,57 +186,50 @@ def test_type_cast(self):
if Is32Bit:
- self.expect_var_path("(void*)0",
- type="void *", value="0x00000000")
- self.expect_var_path("(void*)1",
- type="void *", value="0x00000001")
- self.expect_var_path("(void*)a",
- type="void *", value="0x00000001")
- self.expect_var_path("(void*)na",
- type="void *", value="0xffffffff")
+ self.expect_var_path("(void*)0", type="void *", value="0x00000000")
+ self.expect_var_path("(void*)1", type="void *", value="0x00000001")
+ self.expect_var_path("(void*)a", type="void *", value="0x00000001")
+ self.expect_var_path("(void*)na", type="void *", value="0xffffffff")
else:
- self.expect_var_path("(void*)0",
- type="void *", value="0x0000000000000000")
- self.expect_var_path("(void*)1",
- type="void *", value="0x0000000000000001")
- self.expect_var_path("(void*)a",
- type="void *", value="0x0000000000000001")
- self.expect_var_path("(void*)na",
- type="void *", value="0xffffffffffffffff")
+ self.expect_var_path("(void*)0", type="void *", value="0x0000000000000000")
+ self.expect_var_path("(void*)1", type="void *", value="0x0000000000000001")
+ self.expect_var_path("(void*)a", type="void *", value="0x0000000000000001")
+ self.expect_var_path("(void*)na", type="void *", value="0xffffffffffffffff")
self.expect_var_path("(int*&)ap", type="int *")
- self.expect("frame variable '(char*) 1.0'", error=True,
- substrs=["cannot cast from type 'double' to pointer type"
- " 'char *'"])
+ self.expect(
+ "frame variable '(char*) 1.0'",
+ error=True,
+ substrs=["cannot cast from type 'double' to pointer type 'char *'"],
+ )
self.expect_var_path("*(int*)(void*)ap", type="int", value="1")
self.expect_var_path("(ns::Foo*)ns_inner_foo_ptr_", type="ns::Foo *")
self.expect_var_path("(ns::inner::Foo*)ns_foo_ptr_", type="ns::inner::Foo *")
- self.expect("frame variable '(int& &)ap'", error=True,
- substrs=["type name declared as a reference to a "
- "reference"])
- self.expect("frame variable '(int&*)ap'", error=True,
- substrs=["'type name' declared as a pointer "
- "to a reference of type 'int &'"])
+ self.expect(
+ "frame variable '(int& &)ap'",
+ error=True,
+ substrs=["type name declared as a reference to a reference"],
+ )
+ self.expect(
+ "frame variable '(int&*)ap'",
+ error=True,
+ substrs=[
+ "'type name' declared as a pointer to a reference of type 'int &'"
+ ],
+ )
if Is32Bit:
- self.expect_var_path("(void *)0", type="void *", value="0x00000000")
+ self.expect_var_path("(void *)0", type="void *", value="0x00000000")
else:
- self.expect_var_path("(void *)0", type="void *", value="0x0000000000000000")
+ self.expect_var_path("(void *)0", type="void *", value="0x0000000000000000")
# TestCStyleCastArray
- threads = lldbutil.continue_to_source_breakpoint(
- self, process,"Set a breakpoint here", lldb.SBFileSpec("main.cpp")
- )
- self.assertEqual(
- len(threads), 1, "There should be a thread stopped at our breakpoint"
- )
-
self.expect_var_path("(int*)arr_1d", type="int *")
self.expect_var_path("(char*)arr_1d", type="char *")
self.expect_var_path("((char*)arr_1d)[0]", type="char", value="'\\x01'")
diff --git a/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/main.cpp b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/main.cpp
index 0fd841d95cdf6..6b865badc76e5 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/main.cpp
+++ b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/main.cpp
@@ -57,13 +57,6 @@ int main(int argc, char **argv) {
float fmax = std::numeric_limits<float>::max();
float fdenorm = std::numeric_limits<float>::denorm_min();
- // TestCStyleCastBuiltins
- // TestCStyleCastBasicType
- // TestCStyleCastPointer
- // TestCStyleCastNullptrType
- if (false) { // Set a breakpoint here
- }
-
struct InnerFoo {
int a;
int b;
@@ -75,7 +68,5 @@ int main(int argc, char **argv) {
int arr_1d[] = {1, 2, 3, 4};
int arr_2d[2][3] = {{1, 2, 3}, {4, 5, 6}};
- // TestCStyleCastArray
- // TestCStyleCastReference
return 0; // Set a breakpoint here
}
>From 02e95717ec205943e85b76877b1c7bbc2b48fc73 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Tue, 23 Sep 2025 22:07:10 -0700
Subject: [PATCH 3/7] Remove some redundant type checks. Clean up code
slightly.
---
lldb/source/ValueObject/DILEval.cpp | 41 +++--------------------------
1 file changed, 4 insertions(+), 37 deletions(-)
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index 1daeabb732d43..fe96e19c84bf3 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -672,10 +672,8 @@ llvm::Expected<CompilerType> Interpreter::VerifyCStyleCastType(
uint64_t type_byte_size = 0;
uint64_t rhs_type_byte_size = 0;
if (auto temp = target_type.GetByteSize(m_exe_ctx_scope.get()))
- // type_byte_size = temp.value();
type_byte_size = *temp;
if (auto temp = op_type.GetByteSize(m_exe_ctx_scope.get()))
- // rhs_type_byte_size = temp.value();
rhs_type_byte_size = *temp;
if (!target_type.IsBoolean() && type_byte_size < rhs_type_byte_size) {
std::string errMsg = llvm::formatv(
@@ -784,30 +782,15 @@ Interpreter::Visit(const CStyleCastNode *node) {
switch (cast_kind) {
case CStyleCastKind::eEnumeration: {
- if (!target_type.IsEnumerationType()) {
- std::string errMsg = "invalid ast: target type should be an enumeration.";
- return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
- node->GetLocation());
- }
- if (op_type.IsFloat())
- return operand->CastToEnumType(target_type);
-
- if (op_type.IsInteger() || op_type.IsEnumerationType())
+ if (op_type.IsFloat() || op_type.IsInteger() || op_type.IsEnumerationType())
return operand->CastToEnumType(target_type);
std::string errMsg =
"invalid ast: operand is not convertible to enumeration type";
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
node->GetLocation());
- // return error.ToError();
}
case CStyleCastKind::eNullptr: {
- if (target_type.GetCanonicalType().GetBasicTypeEnumeration() !=
- lldb::eBasicTypeNullPtr) {
- std::string errMsg = "invalid ast: target type should be a nullptr_t.";
- return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
- node->GetLocation());
- }
return ValueObject::CreateValueObjectFromNullptr(m_target, target_type,
"result");
}
@@ -820,33 +803,17 @@ Interpreter::Visit(const CStyleCastNode *node) {
case CStyleCastKind::eNone: {
switch (promo_kind) {
case CastPromoKind::eArithmetic: {
- if (target_type.GetCanonicalType().GetBasicTypeEnumeration() ==
- lldb::eBasicTypeInvalid) {
- std::string errMsg = "invalid ast: target type should be a basic type.";
- return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
- node->GetLocation());
- }
- // Pick an appropriate cast.
- if (op_type.IsPointerType() || op_type.IsNullPtrType()) {
- return operand->CastToBasicType(target_type);
- }
- if (op_type.IsScalarType()) {
- return operand->CastToBasicType(target_type);
- }
- if (op_type.IsEnumerationType()) {
+ if (op_type.IsPointerType() || op_type.IsNullPtrType() ||
+ op_type.IsScalarType() || op_type.IsEnumerationType()) {
return operand->CastToBasicType(target_type);
}
+
std::string errMsg =
"invalid ast: operand is not convertible to arithmetic type";
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
node->GetLocation());
}
case CastPromoKind::ePointer: {
- if (!target_type.IsPointerType()) {
- std::string errMsg = "invalid ast: target type should be a pointer";
- return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
- node->GetLocation());
- }
uint64_t addr =
op_type.IsArrayType()
? operand->GetLoadAddress()
>From fd3f8f5300266d9a88c78247840b5a721ad2ffce Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Tue, 23 Sep 2025 22:21:47 -0700
Subject: [PATCH 4/7] Fix more clang-format issues.
---
.../LocalVars/TestFrameVarDILLocalVars.py | 1 -
.../CStyleCast/TestFrameVarDILCStyleCast.py | 29 ++++++++-----------
2 files changed, 12 insertions(+), 18 deletions(-)
diff --git a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
index e142b654b00e6..85899caaa7433 100644
--- a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
+++ b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
@@ -12,7 +12,6 @@
import time
-
class TestFrameVarDILLocalVars(TestBase):
# If your test case doesn't stress debug info, then
# set this to true. That way it won't be run once for
diff --git a/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py
index 6c2f0eb77ce0c..edf0194cc8dfb 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py
+++ b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py
@@ -11,8 +11,8 @@
import shutil
import time
-class TestFrameVarDILCStyleCast(TestBase):
+class TestFrameVarDILCStyleCast(TestBase):
def test_type_cast(self):
self.build()
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
@@ -104,9 +104,7 @@ def test_type_cast(self):
self.expect(
"frame variable '(int)ns_foo_'",
error=True,
- substrs=[
- "cannot convert 'ns::Foo' to 'int' without a conversion operator"
- ],
+ substrs=["cannot convert 'ns::Foo' to 'int' without a conversion operator"],
)
# Test with typedefs and namespaces.
@@ -152,7 +150,7 @@ def test_type_cast(self):
)
Is32Bit = False
if self.target().GetAddressByteSize() == 4:
- Is32Bit = True;
+ Is32Bit = True
if Is32Bit:
self.expect("frame variable '(int)arr'", type="int")
@@ -160,9 +158,7 @@ def test_type_cast(self):
self.expect(
"frame variable '(int)arr'",
error=True,
- substrs=[
- "cast from pointer to smaller type 'int' loses information"
- ],
+ substrs=["cast from pointer to smaller type 'int' loses information"],
)
self.expect(
@@ -186,15 +182,15 @@ def test_type_cast(self):
if Is32Bit:
- self.expect_var_path("(void*)0", type="void *", value="0x00000000")
- self.expect_var_path("(void*)1", type="void *", value="0x00000001")
- self.expect_var_path("(void*)a", type="void *", value="0x00000001")
- self.expect_var_path("(void*)na", type="void *", value="0xffffffff")
+ self.expect_var_path("(void*)0", type="void *", value="0x00000000")
+ self.expect_var_path("(void*)1", type="void *", value="0x00000001")
+ self.expect_var_path("(void*)a", type="void *", value="0x00000001")
+ self.expect_var_path("(void*)na", type="void *", value="0xffffffff")
else:
- self.expect_var_path("(void*)0", type="void *", value="0x0000000000000000")
- self.expect_var_path("(void*)1", type="void *", value="0x0000000000000001")
- self.expect_var_path("(void*)a", type="void *", value="0x0000000000000001")
- self.expect_var_path("(void*)na", type="void *", value="0xffffffffffffffff")
+ self.expect_var_path("(void*)0", type="void *", value="0x0000000000000000")
+ self.expect_var_path("(void*)1", type="void *", value="0x0000000000000001")
+ self.expect_var_path("(void*)a", type="void *", value="0x0000000000000001")
+ self.expect_var_path("(void*)na", type="void *", value="0xffffffffffffffff")
self.expect_var_path("(int*&)ap", type="int *")
@@ -227,7 +223,6 @@ def test_type_cast(self):
else:
self.expect_var_path("(void *)0", type="void *", value="0x0000000000000000")
-
# TestCStyleCastArray
self.expect_var_path("(int*)arr_1d", type="int *")
>From 77e940c82f5b75b2da90c946606f116d9ea3ee17 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Tue, 23 Sep 2025 22:25:44 -0700
Subject: [PATCH 5/7] Fix formatting.
---
.../frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py
index edf0194cc8dfb..84b4ecff508a4 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py
+++ b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py
@@ -180,7 +180,6 @@ def test_type_cast(self):
self.expect_var_path("(unsigned long long*)vp", type="unsigned long long *")
self.expect_var_path("(unsigned short int*)vp", type="unsigned short *")
-
if Is32Bit:
self.expect_var_path("(void*)0", type="void *", value="0x00000000")
self.expect_var_path("(void*)1", type="void *", value="0x00000001")
>From d13cda61ac5cb3b1d7c50ec1b6f11af8aa961930 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Thu, 25 Sep 2025 16:54:53 -0700
Subject: [PATCH 6/7] Remove commented out code & extra ';' Update
ResolveTypeByName to return immediately when full match is found. Remove
'DIL' prefix from GetTypeSystemFromCU.
---
lldb/include/lldb/ValueObject/DILParser.h | 2 +-
lldb/source/ValueObject/DILEval.cpp | 4 ++--
lldb/source/ValueObject/DILParser.cpp | 22 ++++++----------------
3 files changed, 9 insertions(+), 19 deletions(-)
diff --git a/lldb/include/lldb/ValueObject/DILParser.h b/lldb/include/lldb/ValueObject/DILParser.h
index 3128398d9055e..0a1a8c1c58b85 100644
--- a/lldb/include/lldb/ValueObject/DILParser.h
+++ b/lldb/include/lldb/ValueObject/DILParser.h
@@ -33,7 +33,7 @@ enum class ErrorCode : unsigned char {
};
llvm::Expected<lldb::TypeSystemSP>
-DILGetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx);
+GetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx);
// The following is modeled on class OptionParseError.
class DILDiagnosticError
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index fe96e19c84bf3..37fa3ca52300c 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -586,7 +586,7 @@ Interpreter::PickIntegerType(lldb::TypeSystemSP type_system,
llvm::Expected<lldb::ValueObjectSP>
Interpreter::Visit(const IntegerLiteralNode *node) {
llvm::Expected<lldb::TypeSystemSP> type_system =
- DILGetTypeSystemFromCU(m_exe_ctx_scope);
+ GetTypeSystemFromCU(m_exe_ctx_scope);
if (!type_system)
return type_system.takeError();
@@ -610,7 +610,7 @@ Interpreter::Visit(const IntegerLiteralNode *node) {
llvm::Expected<lldb::ValueObjectSP>
Interpreter::Visit(const FloatLiteralNode *node) {
llvm::Expected<lldb::TypeSystemSP> type_system =
- DILGetTypeSystemFromCU(m_exe_ctx_scope);
+ GetTypeSystemFromCU(m_exe_ctx_scope);
if (!type_system)
return type_system.takeError();
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index e4e40a5869831..72d98aef5eaee 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -45,7 +45,7 @@ DILDiagnosticError::DILDiagnosticError(llvm::StringRef expr,
}
llvm::Expected<lldb::TypeSystemSP>
-DILGetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx) {
+GetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx) {
SymbolContext symbol_context =
ctx->GetSymbolContext(lldb::eSymbolContextCompUnit);
lldb::LanguageType language = symbol_context.comp_unit->GetLanguage();
@@ -102,18 +102,14 @@ ResolveTypeByName(const std::string &name,
for (uint32_t i = 0; i < result_type_list.size(); ++i) {
CompilerType type = result_type_list[i];
llvm::StringRef type_name_ref = type.GetTypeName().GetStringRef();
- ;
- if (type_name_ref == name_ref)
- full_match = type;
- else if (type_name_ref.ends_with(name_ref))
+ if (type_name_ref == name_ref && type.IsValid())
+ return type;
+
+ if (type_name_ref.ends_with(name_ref))
partial_matches.push_back(type);
}
- // Full match is always correct.
- if (full_match.IsValid())
- return full_match;
-
// If we have partial matches, pick a "random" one.
if (partial_matches.size() > 0)
return partial_matches.back();
@@ -198,8 +194,6 @@ ASTNodeUP DILParser::ParseCastExpression() {
m_dil_lexer.Advance();
auto rhs = ParseCastExpression();
- // return BuildCStyleCast(type_id.value(), std::move(rhs),
- // token.GetLocation());
return std::make_unique<CStyleCastNode>(
loc, type_id.value(), std::move(rhs), CStyleCastKind::eNone);
}
@@ -436,7 +430,7 @@ std::optional<CompilerType> DILParser::ParseTypeId(bool must_be_type_id) {
CompilerType type;
if (type_decl.m_is_builtin) {
llvm::Expected<lldb::TypeSystemSP> type_system =
- DILGetTypeSystemFromCU(m_ctx_scope);
+ GetTypeSystemFromCU(m_ctx_scope);
if (!type_system)
return {};
// type = GetBasicType(m_ctx_scope, type_decl.GetBasicType());
@@ -751,11 +745,7 @@ bool DILParser::HandleSimpleTypeSpecifier(TypeDeclaration *type_decl) {
uint32_t loc = CurToken().GetLocation();
std::string kind = CurToken().GetSpelling();
- // switch (kind) {
if (kind == "int") {
- // case Token::kw_int: {
- // "int" can have signedness and be combined with "short", "long" and
- // "long long" (but not with another "int").
if (type_decl->m_has_int_specifier) {
BailOut("cannot combine with previous 'int' declaration specifier", loc,
CurToken().GetSpelling().length());
>From c2bc4f0c5f16fbcf6add4d4b9528e7ff0c481046 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Fri, 3 Oct 2025 16:05:49 -0700
Subject: [PATCH 7/7] Simplify parsing of builtin type names.
Following a reviewer suggestion. This eliminates the need for the
TypeSpecifier & TypeDeclaration classes which simplifies things
a bit.
---
lldb/include/lldb/ValueObject/DILParser.h | 126 +------
lldb/source/ValueObject/DILParser.cpp | 406 +++-------------------
2 files changed, 58 insertions(+), 474 deletions(-)
diff --git a/lldb/include/lldb/ValueObject/DILParser.h b/lldb/include/lldb/ValueObject/DILParser.h
index 0a1a8c1c58b85..0a3ea58cb3d04 100644
--- a/lldb/include/lldb/ValueObject/DILParser.h
+++ b/lldb/include/lldb/ValueObject/DILParser.h
@@ -59,61 +59,6 @@ class DILDiagnosticError
std::string message() const override { return m_detail.rendered; }
};
-/// TypeDeclaration builds information about the literal type definition as
-/// type is being parsed. It doesn't perform semantic analysis for non-basic
-/// types -- e.g. "char&&&" is a valid type declaration.
-/// NOTE: CV qualifiers are ignored.
-class TypeDeclaration {
-public:
- enum class TypeSpecifier {
- kBool,
- kChar,
- kDouble,
- kFloat,
- kInt,
- kLong,
- kLongDouble,
- kLongLong,
- kShort,
- kUnknown,
- kVoid,
- };
-
- enum class SignSpecifier {
- kUnknown,
- kSigned,
- kUnsigned,
- };
-
- bool IsEmpty() const { return !m_is_builtin && !m_is_user_type; }
-
- lldb::BasicType GetBasicType() const;
-
-public:
- // Indicates user-defined typename (e.g. "MyClass", "MyTmpl<int>").
- std::string m_user_typename;
-
- // Basic type specifier ("void", "char", "intr", "float", "long long", etc.).
- TypeSpecifier m_type_specifier = TypeSpecifier::kUnknown;
-
- // Signedness specifier ("signed", "unsigned").
- SignSpecifier m_sign_specifier = SignSpecifier::kUnknown;
-
- // Does the type declaration includes "int" specifier?
- // This is different than `type_specifier_` and is used to detect "int"
- // duplication for types that can be combined with "int" specifier (e.g.
- // "short int", "long int").
- bool m_has_int_specifier = false;
-
- // Indicates whether there was an error during parsing.
- bool m_has_error = false;
-
- // Indicates whether this declaration describes a builtin type.
- bool m_is_builtin = false;
-
- // Indicates whether this declaration describes a user type.
- bool m_is_user_type = false;
-}; // class TypeDeclaration
/// Pure recursive descent parser for C++ like expressions.
/// EBNF grammar for the parser is described in lldb/docs/dil-expr-lang.ebnf
@@ -161,14 +106,13 @@ class DILParser {
ASTNodeUP ParseBooleanLiteral();
ASTNodeUP ParseCastExpression();
- std::optional<CompilerType> ParseTypeId(bool must_be_type_id = false);
- void ParseTypeSpecifierSeq(TypeDeclaration *type_decl);
- bool ParseTypeSpecifier(TypeDeclaration *type_decl);
+ std::optional<CompilerType> ParseBuiltinType();
+ std::optional<CompilerType> ParseTypeId();
+ void ParseTypeSpecifierSeq(std::string &type_name);
+ bool ParseTypeSpecifier(std::string &user_type_name);
std::string ParseTypeName();
CompilerType ResolveTypeDeclarators(CompilerType type,
const std::vector<Token> &ptr_operators);
- bool IsSimpleTypeSpecifierKeyword(Token token) const;
- bool HandleSimpleTypeSpecifier(TypeDeclaration *type_decl);
void BailOut(const std::string &error, uint32_t loc, uint16_t err_len);
@@ -204,66 +148,4 @@ class DILParser {
} // namespace lldb_private::dil
-namespace llvm {
-template <>
-struct format_provider<lldb_private::dil::TypeDeclaration::TypeSpecifier> {
- static void format(const lldb_private::dil::TypeDeclaration::TypeSpecifier &t,
- raw_ostream &OS, llvm::StringRef Options) {
- switch (t) {
- case lldb_private::dil::TypeDeclaration::TypeSpecifier::kVoid:
- OS << "void";
- break;
- case lldb_private::dil::TypeDeclaration::TypeSpecifier::kBool:
- OS << "bool";
- break;
- case lldb_private::dil::TypeDeclaration::TypeSpecifier::kChar:
- OS << "char";
- break;
- case lldb_private::dil::TypeDeclaration::TypeSpecifier::kInt:
- OS << "int";
- break;
- case lldb_private::dil::TypeDeclaration::TypeSpecifier::kFloat:
- OS << "float";
- break;
- case lldb_private::dil::TypeDeclaration::TypeSpecifier::kShort:
- OS << "short";
- break;
- case lldb_private::dil::TypeDeclaration::TypeSpecifier::kLong:
- OS << "long";
- break;
- case lldb_private::dil::TypeDeclaration::TypeSpecifier::kLongLong:
- OS << "long long";
- break;
- case lldb_private::dil::TypeDeclaration::TypeSpecifier::kDouble:
- OS << "double";
- break;
- case lldb_private::dil::TypeDeclaration::TypeSpecifier::kLongDouble:
- OS << "long double";
- break;
- default:
- OS << "invalid type specifier";
- break;
- }
- }
-};
-
-template <>
-struct format_provider<lldb_private::dil::TypeDeclaration::SignSpecifier> {
- static void format(const lldb_private::dil::TypeDeclaration::SignSpecifier &t,
- raw_ostream &OS, llvm::StringRef Options) {
- switch (t) {
- case lldb_private::dil::TypeDeclaration::SignSpecifier::kSigned:
- OS << "signed";
- break;
- case lldb_private::dil::TypeDeclaration::SignSpecifier::kUnsigned:
- OS << "unsigned";
- break;
- default:
- OS << "invalid sign specifier";
- break;
- }
- }
-};
-} // namespace llvm
-
#endif // LLDB_VALUEOBJECT_DILPARSER_H
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index 72d98aef5eaee..61af022d337d1 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -86,13 +86,6 @@ ResolveTypeByName(const std::string &name,
}
}
}
-
- if (result_type_list.empty()) {
- for (auto type_system_sp : target_sp->GetScratchTypeSystems())
- if (auto compiler_type =
- type_system_sp->GetBuiltinTypeByName(const_type_name))
- result_type_list.push_back(compiler_type);
- }
}
// We've found multiple types, try finding the "correct" one.
@@ -396,88 +389,66 @@ std::string DILParser::ParseNestedNameSpecifier() {
}
}
-// Parse a type_id.
-//
-// type_id:
-// type_specifier_seq [abstract_declarator]
-std::optional<CompilerType> DILParser::ParseTypeId(bool must_be_type_id) {
- uint32_t type_loc = CurToken().GetLocation();
- TypeDeclaration type_decl;
-
- // type_specifier_seq is required here, start with trying to parse it.
- ParseTypeSpecifierSeq(&type_decl);
-
- if (type_decl.IsEmpty()) {
- // TODO: Should we bail out if `must_be_type_id` is set?
- return {};
+// Parse a built-in type
+//
+// A built-in type can be a single identifier or a space-separated
+// list of identifiers (e.g. "short" or "long long").
+std::optional<CompilerType> DILParser::ParseBuiltinType() {
+ std::string type_name = "";
+ uint32_t save_token_idx = m_dil_lexer.GetCurrentTokenIdx();
+ bool first_word = true;
+ while (CurToken().GetKind() == Token::identifier) {
+ if (CurToken().GetSpelling() == "const" ||
+ CurToken().GetSpelling() == "volatile")
+ continue;
+ if (!first_word)
+ type_name.push_back(' ');
+ else
+ first_word = false;
+ type_name.append(CurToken().GetSpelling());
+ m_dil_lexer.Advance();
}
- if (type_decl.m_has_error) {
- if (type_decl.m_is_builtin) {
- return {};
- }
-
- assert(type_decl.m_is_user_type && "type_decl must be a user type");
- // Found something looking like a user type, but failed to parse it.
- // Return invalid type if we expect to have a type here, otherwise nullopt.
- if (must_be_type_id) {
- return {};
- }
- return {};
+ if (type_name.size() > 0) {
+ lldb::TargetSP target_sp = m_ctx_scope->CalculateTarget();
+ ConstString const_type_name(type_name.c_str());
+ for (auto type_system_sp : target_sp->GetScratchTypeSystems())
+ if (auto compiler_type =
+ type_system_sp->GetBuiltinTypeByName(const_type_name))
+ return compiler_type;
}
- // Try to resolve the base type.
- CompilerType type;
- if (type_decl.m_is_builtin) {
- llvm::Expected<lldb::TypeSystemSP> type_system =
- GetTypeSystemFromCU(m_ctx_scope);
- if (!type_system)
- return {};
- // type = GetBasicType(m_ctx_scope, type_decl.GetBasicType());
- // type = DILGetBasicType(*type_system, type_decl.GetBasicType());
- type = (*type_system).get()->GetBasicTypeFromAST(type_decl.GetBasicType());
- assert(type.IsValid() && "cannot resolve basic type");
+ TentativeParsingRollback(save_token_idx);
+ return {};
+}
+std::optional<CompilerType> DILParser::ParseTypeId() {
+ CompilerType type;
+ auto maybe_builtin_type = ParseBuiltinType();
+ if (maybe_builtin_type) {
+ type = *maybe_builtin_type;
} else {
- assert(type_decl.m_is_user_type && "type_decl must be a user type");
- type = ResolveTypeByName(type_decl.m_user_typename, m_ctx_scope);
- if (!type.IsValid()) {
- if (must_be_type_id) {
- BailOut(
- llvm::formatv("unknown type name '{0}'", type_decl.m_user_typename),
- type_loc, CurToken().GetSpelling().length());
- return {};
- }
+ // Check to see if we have a user-defined type here.
+ // First build up the user-defined type name.
+ std::string type_name;
+ ParseTypeSpecifierSeq(type_name);
+
+ if (type_name.size() == 0)
+ return {};
+ type = ResolveTypeByName(type_name, m_ctx_scope);
+ if (!type.IsValid())
return {};
- }
- if (LookupIdentifier(type_decl.m_user_typename, m_ctx_scope,
- m_use_dynamic)) {
- // Same-name identifiers should be preferred over typenames.
+ // Same-name identifiers should be preferred over typenames.
+ if (LookupIdentifier(type_name, m_ctx_scope, m_use_dynamic))
// TODO: Make type accessible with 'class', 'struct' and 'union' keywords.
- if (must_be_type_id) {
- BailOut(llvm::formatv(
- "must use '{0}' tag to refer to type '{1}' in this scope",
- type.GetTypeTag(), type_decl.m_user_typename),
- type_loc, CurToken().GetSpelling().length());
- return {};
- }
return {};
- }
- if (LookupGlobalIdentifier(type_decl.m_user_typename, m_ctx_scope,
- m_ctx_scope->CalculateTarget(), m_use_dynamic)) {
- // Same-name identifiers should be preferred over typenames.
- // TODO: Make type accessible with 'class', 'struct' and 'union' keywords.
- if (must_be_type_id) {
- BailOut(llvm::formatv(
- "must use '{0}' tag to refer to type '{1}' in this scope",
- type.GetTypeTag(), type_decl.m_user_typename),
- type_loc, CurToken().GetSpelling().length());
- return {};
- }
+ // Same-name identifiers should be preferred over typenames.
+ if (LookupGlobalIdentifier(type_name, m_ctx_scope,
+ m_ctx_scope->CalculateTarget(), m_use_dynamic))
+ // TODO: Make type accessible with 'class', 'struct' and 'union' keywords
return {};
- }
}
//
@@ -500,9 +471,9 @@ std::optional<CompilerType> DILParser::ParseTypeId(bool must_be_type_id) {
// type_specifier_seq:
// type_specifier [type_specifier_seq]
//
-void DILParser::ParseTypeSpecifierSeq(TypeDeclaration *type_decl) {
+void DILParser::ParseTypeSpecifierSeq(std::string &type_name) {
while (true) {
- bool type_specifier = ParseTypeSpecifier(type_decl);
+ bool type_specifier = ParseTypeSpecifier(type_name);
if (!type_specifier) {
break;
}
@@ -512,41 +483,11 @@ void DILParser::ParseTypeSpecifierSeq(TypeDeclaration *type_decl) {
// Parse a type_specifier.
//
// type_specifier:
-// simple_type_specifier
-// cv_qualifier
-//
-// simple_type_specifier:
// ["::"] [nested_name_specifier] type_name
-// "char"
-// "bool"
-// "integer"
-// "float"
-// "void"
//
// Returns TRUE if a type_specifier was successfully parsed at this location.
//
-bool DILParser::ParseTypeSpecifier(TypeDeclaration *type_decl) {
- if (IsSimpleTypeSpecifierKeyword(CurToken())) {
- // User-defined typenames can't be combined with builtin keywords.
- if (type_decl->m_is_user_type) {
- BailOut("cannot combine with previous declaration specifier",
- CurToken().GetLocation(), CurToken().GetSpelling().length());
- type_decl->m_has_error = true;
- return false;
- }
-
- // From now on this type declaration must describe a builtin type.
- // TODO: Should this be allowed -- `unsigned myint`?
- type_decl->m_is_builtin = true;
-
- if (!HandleSimpleTypeSpecifier(type_decl)) {
- type_decl->m_has_error = true;
- return false;
- }
- m_dil_lexer.Advance();
- return true;
- }
-
+bool DILParser::ParseTypeSpecifier(std::string &user_type_name) {
// The type_specifier must be a user-defined type. Try parsing a
// simple_type_specifier.
{
@@ -557,7 +498,7 @@ bool DILParser::ParseTypeSpecifier(TypeDeclaration *type_decl) {
m_dil_lexer.Advance();
}
- uint32_t loc = CurToken().GetLocation();
+ // uint32_t loc = CurToken().GetLocation();
// Try parsing optional nested_name_specifier.
auto nested_name_specifier = ParseNestedNameSpecifier();
@@ -570,25 +511,8 @@ bool DILParser::ParseTypeSpecifier(TypeDeclaration *type_decl) {
// optional. In this case type_name is type we're looking for.
if (!type_name.empty()) {
// User-defined typenames can't be combined with builtin keywords.
- if (type_decl->m_is_builtin) {
- BailOut("cannot combine with previous declaration specifier", loc,
- CurToken().GetSpelling().length());
- type_decl->m_has_error = true;
- return false;
- }
- // There should be only one user-defined typename.
- if (type_decl->m_is_user_type) {
- BailOut("two or more data types in declaration of 'type name'", loc,
- CurToken().GetSpelling().length());
- type_decl->m_has_error = true;
- return false;
- }
-
- // Construct the fully qualified typename.
- type_decl->m_is_user_type = true;
- type_decl->m_user_typename =
- llvm::formatv("{0}{1}{2}", global_scope ? "::" : "",
- nested_name_specifier, type_name);
+ user_type_name = llvm::formatv("{0}{1}{2}", global_scope ? "::" : "",
+ nested_name_specifier, type_name);
return true;
}
}
@@ -725,166 +649,6 @@ DILParser::ResolveTypeDeclarators(CompilerType type,
return type;
}
-bool DILParser::IsSimpleTypeSpecifierKeyword(Token token) const {
- if (token.GetKind() != Token::identifier)
- return false;
- if (token.GetSpelling() == "bool" || token.GetSpelling() == "char" ||
- token.GetSpelling() == "int" || token.GetSpelling() == "float" ||
- token.GetSpelling() == "void" || token.GetSpelling() == "short" ||
- token.GetSpelling() == "long" || token.GetSpelling() == "signed" ||
- token.GetSpelling() == "unsigned" || token.GetSpelling() == "double")
- return true;
- return false;
-}
-
-bool DILParser::HandleSimpleTypeSpecifier(TypeDeclaration *type_decl) {
- using TypeSpecifier = TypeDeclaration::TypeSpecifier;
- using SignSpecifier = TypeDeclaration::SignSpecifier;
-
- TypeSpecifier type_spec = type_decl->m_type_specifier;
- uint32_t loc = CurToken().GetLocation();
- std::string kind = CurToken().GetSpelling();
-
- if (kind == "int") {
- if (type_decl->m_has_int_specifier) {
- BailOut("cannot combine with previous 'int' declaration specifier", loc,
- CurToken().GetSpelling().length());
- return false;
- }
- if (type_spec == TypeSpecifier::kShort ||
- type_spec == TypeSpecifier::kLong ||
- type_spec == TypeSpecifier::kLongLong) {
- type_decl->m_has_int_specifier = true;
- return true;
- } else if (type_spec == TypeSpecifier::kUnknown) {
- type_decl->m_type_specifier = TypeSpecifier::kInt;
- type_decl->m_has_int_specifier = true;
- return true;
- }
- BailOut(llvm::formatv(
- "cannot combine with previous '{0}' declaration specifier",
- type_spec),
- loc, CurToken().GetSpelling().length());
- return false;
- }
-
- if (kind == "long") {
- // "long" can have signedness and be combined with "int" or "long" to
- // form "long long".
- if (type_spec == TypeSpecifier::kUnknown ||
- type_spec == TypeSpecifier::kInt) {
- type_decl->m_type_specifier = TypeSpecifier::kLong;
- return true;
- } else if (type_spec == TypeSpecifier::kLong) {
- type_decl->m_type_specifier = TypeSpecifier::kLongLong;
- return true;
- } else if (type_spec == TypeSpecifier::kDouble) {
- type_decl->m_type_specifier = TypeSpecifier::kLongDouble;
- return true;
- }
- BailOut(llvm::formatv(
- "cannot combine with previous '{0}' declaration specifier",
- type_spec),
- loc, CurToken().GetSpelling().length());
- return false;
- }
-
- if (kind == "short") {
- // "short" can have signedness and be combined with "int".
- if (type_spec == TypeSpecifier::kUnknown ||
- type_spec == TypeSpecifier::kInt) {
- type_decl->m_type_specifier = TypeSpecifier::kShort;
- return true;
- }
- BailOut(llvm::formatv(
- "cannot combine with previous '{0}' declaration specifier",
- type_spec),
- loc, CurToken().GetSpelling().length());
- return false;
- }
-
- if (kind == "char") {
- // "char" can have signedness, but it cannot be combined with any other
- // type specifier.
- if (type_spec == TypeSpecifier::kUnknown) {
- type_decl->m_type_specifier = TypeSpecifier::kChar;
- return true;
- }
- BailOut(llvm::formatv(
- "cannot combine with previous '{0}' declaration specifier",
- type_spec),
- loc, CurToken().GetSpelling().length());
- return false;
- }
-
- if (kind == "double") {
- // "double" can be combined with "long" to form "long double", but it
- // cannot be combined with signedness specifier.
- if (type_decl->m_sign_specifier != SignSpecifier::kUnknown) {
- BailOut("'double' cannot be signed or unsigned", loc,
- CurToken().GetSpelling().length());
- return false;
- }
- if (type_spec == TypeSpecifier::kUnknown) {
- type_decl->m_type_specifier = TypeSpecifier::kDouble;
- return true;
- } else if (type_spec == TypeSpecifier::kLong) {
- type_decl->m_type_specifier = TypeSpecifier::kLongDouble;
- return true;
- }
- BailOut(llvm::formatv(
- "cannot combine with previous '{0}' declaration specifier",
- type_spec),
- loc, CurToken().GetSpelling().length());
- return false;
- }
-
- if (kind == "bool" || kind == "void" || kind == "float") {
- // These types cannot have signedness or be combined with any other type
- // specifiers.
- if (type_decl->m_sign_specifier != SignSpecifier::kUnknown) {
- BailOut(llvm::formatv("'{0}' cannot be signed or unsigned", kind), loc,
- CurToken().GetSpelling().length());
- return false;
- }
- if (type_spec != TypeSpecifier::kUnknown) {
- BailOut(llvm::formatv(
- "cannot combine with previous '{0}' declaration specifier",
- type_spec),
- loc, CurToken().GetSpelling().length());
- }
- if (kind == "bool")
- type_decl->m_type_specifier = TypeSpecifier::kBool;
- else if (kind == "void")
- type_decl->m_type_specifier = TypeSpecifier::kVoid;
- else if (kind == "float")
- type_decl->m_type_specifier = TypeSpecifier::kFloat;
- return true;
- }
-
- if (kind == "signed" || kind == "unsigned") {
- // "signed" and "unsigned" cannot be combined with another signedness
- // specifier.
- if (type_spec == TypeSpecifier::kVoid ||
- type_spec == TypeSpecifier::kBool ||
- type_spec == TypeSpecifier::kFloat ||
- type_spec == TypeSpecifier::kDouble ||
- type_spec == TypeSpecifier::kLongDouble) {
- BailOut(llvm::formatv("'{0}' cannot be signed or unsigned", type_spec),
- loc, CurToken().GetSpelling().length());
- return false;
- }
-
- type_decl->m_sign_specifier =
- (kind == "signed") ? SignSpecifier::kSigned : SignSpecifier::kUnsigned;
- return true;
- }
-
- BailOut(llvm::formatv("invalid simple type specifier kind"), loc,
- CurToken().GetSpelling().length());
- return false;
-}
-
// Parse an boolean_literal.
//
// boolean_literal:
@@ -1015,66 +779,4 @@ void DILParser::ExpectOneOf(std::vector<Token::Kind> kinds_vec) {
}
}
-lldb::BasicType TypeDeclaration::GetBasicType() const {
- if (!m_is_builtin)
- return lldb::eBasicTypeInvalid;
-
- if (m_sign_specifier == SignSpecifier::kSigned &&
- m_type_specifier == TypeSpecifier::kChar) {
- // "signed char" isn't the same as "char".
- return lldb::eBasicTypeSignedChar;
- }
-
- if (m_sign_specifier == SignSpecifier::kUnsigned) {
- switch (m_type_specifier) {
- // "unsigned" is "unsigned int"
- case TypeSpecifier::kUnknown:
- return lldb::eBasicTypeUnsignedInt;
- case TypeSpecifier::kChar:
- return lldb::eBasicTypeUnsignedChar;
- case TypeSpecifier::kShort:
- return lldb::eBasicTypeUnsignedShort;
- case TypeSpecifier::kInt:
- return lldb::eBasicTypeUnsignedInt;
- case TypeSpecifier::kLong:
- return lldb::eBasicTypeUnsignedLong;
- case TypeSpecifier::kLongLong:
- return lldb::eBasicTypeUnsignedLongLong;
- default:
- // assert(false && "unknown unsigned basic type");
- return lldb::eBasicTypeInvalid;
- }
- }
-
- switch (m_type_specifier) {
- case TypeSpecifier::kUnknown:
- // "signed" is "signed int"
- if (m_sign_specifier != SignSpecifier::kSigned)
- return lldb::eBasicTypeInvalid;
- return lldb::eBasicTypeInt;
- case TypeSpecifier::kVoid:
- return lldb::eBasicTypeVoid;
- case TypeSpecifier::kBool:
- return lldb::eBasicTypeBool;
- case TypeSpecifier::kChar:
- return lldb::eBasicTypeChar;
- case TypeSpecifier::kShort:
- return lldb::eBasicTypeShort;
- case TypeSpecifier::kInt:
- return lldb::eBasicTypeInt;
- case TypeSpecifier::kLong:
- return lldb::eBasicTypeLong;
- case TypeSpecifier::kLongLong:
- return lldb::eBasicTypeLongLong;
- case TypeSpecifier::kFloat:
- return lldb::eBasicTypeFloat;
- case TypeSpecifier::kDouble:
- return lldb::eBasicTypeDouble;
- case TypeSpecifier::kLongDouble:
- return lldb::eBasicTypeLongDouble;
- }
-
- return lldb::eBasicTypeInvalid;
-}
-
} // namespace lldb_private::dil
More information about the lldb-commits
mailing list