Skip to content

Commit bbacb82

Browse files
committed
[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.
1 parent fc0f1fc commit bbacb82

File tree

11 files changed

+1439
-18
lines changed

11 files changed

+1439
-18
lines changed

lldb/docs/dil-expr-lang.ebnf

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
(* This is currently a subset of the final DIL Language, matching the current
44
DIL implementation. *)
55
6-
expression = unary_expression ;
6+
expression = cast_expression;
7+
8+
cast_expression = unary_expression
9+
| "(" type_id ")" cast_expression;
710
811
unary_expression = postfix_expression
9-
| unary_operator expression ;
12+
| unary_operator cast_expression ;
1013
1114
unary_operator = "*" | "&" ;
1215
@@ -41,6 +44,31 @@ nested_name_specifier = type_name "::"
4144
| namespace_name '::'
4245
| nested_name_specifier identifier "::" ;
4346
47+
type_id = type_specifier_seq [abstract_declarator] ;
48+
49+
type_specifier_seq = type_specifier [type_specifier];
50+
51+
type_specifier = ["::"] [nested_name_specifier] type_name;
52+
| "char"
53+
| "bool"
54+
| "short"
55+
| "int"
56+
| "long"
57+
| "signed"
58+
| "unsigned"
59+
| "float"
60+
| "double"
61+
| "void" ;
62+
63+
nested_name_specifier = type_name "::"
64+
| namespace_name "::"
65+
| nested_name_specifier identifier "::" ;
66+
67+
abstract_declarator = ptr_operator [abstract_declarator] ;
68+
69+
ptr_operator = "*"
70+
| "&";
71+
4472
type_name = class_name
4573
| enum_name
4674
| typedef_name;

lldb/include/lldb/ValueObject/DILAST.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ namespace lldb_private::dil {
2020
enum class NodeKind {
2121
eArraySubscriptNode,
2222
eBitExtractionNode,
23+
eCStyleCastNode,
2324
eErrorNode,
2425
eFloatLiteralNode,
2526
eIdentifierNode,
@@ -28,6 +29,21 @@ enum class NodeKind {
2829
eUnaryOpNode,
2930
};
3031

32+
/// The C-Style casts allowed by DIL.
33+
enum class CStyleCastKind {
34+
eEnumeration,
35+
eNullptr,
36+
eReference,
37+
eNone,
38+
};
39+
40+
/// Promotions for C-Style casts in DIL.
41+
enum class CastPromoKind {
42+
eArithmetic,
43+
ePointer,
44+
eNone,
45+
};
46+
3147
/// The Unary operators recognized by DIL.
3248
enum class UnaryOpKind {
3349
AddrOf, // "&"
@@ -226,6 +242,29 @@ class FloatLiteralNode : public ASTNode {
226242
llvm::APFloat m_value;
227243
};
228244

245+
class CStyleCastNode : public ASTNode {
246+
public:
247+
CStyleCastNode(uint32_t location, CompilerType type, ASTNodeUP operand,
248+
CStyleCastKind kind)
249+
: ASTNode(location, NodeKind::eCStyleCastNode), m_type(type),
250+
m_operand(std::move(operand)), m_cast_kind(kind) {}
251+
252+
llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
253+
254+
CompilerType GetType() const { return m_type; }
255+
ASTNode *GetOperand() const { return m_operand.get(); }
256+
CStyleCastKind GetCastKind() const { return m_cast_kind; }
257+
258+
static bool classof(const ASTNode *node) {
259+
return node->GetKind() == NodeKind::eCStyleCastNode;
260+
}
261+
262+
private:
263+
CompilerType m_type;
264+
ASTNodeUP m_operand;
265+
CStyleCastKind m_cast_kind;
266+
};
267+
229268
/// This class contains one Visit method for each specialized type of
230269
/// DIL AST node. The Visit methods are used to dispatch a DIL AST node to
231270
/// the correct function in the DIL expression evaluator for evaluating that
@@ -247,6 +286,8 @@ class Visitor {
247286
Visit(const IntegerLiteralNode *node) = 0;
248287
virtual llvm::Expected<lldb::ValueObjectSP>
249288
Visit(const FloatLiteralNode *node) = 0;
289+
virtual llvm::Expected<lldb::ValueObjectSP>
290+
Visit(const CStyleCastNode *node) = 0;
250291
};
251292

252293
} // namespace lldb_private::dil

lldb/include/lldb/ValueObject/DILEval.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,19 @@ class Interpreter : Visitor {
5858
Visit(const IntegerLiteralNode *node) override;
5959
llvm::Expected<lldb::ValueObjectSP>
6060
Visit(const FloatLiteralNode *node) override;
61+
llvm::Expected<lldb::ValueObjectSP>
62+
Visit(const CStyleCastNode *node) override;
6163

6264
llvm::Expected<CompilerType>
6365
PickIntegerType(lldb::TypeSystemSP type_system,
6466
std::shared_ptr<ExecutionContextScope> ctx,
6567
const IntegerLiteralNode *literal);
6668

69+
llvm::Expected<CompilerType>
70+
VerifyCStyleCastType(lldb::ValueObjectSP &operand, CompilerType &op_type,
71+
CompilerType target_type, CastPromoKind &promo_kind,
72+
CStyleCastKind &cast_kind, int location);
73+
6774
// Used by the interpreter to create objects, perform casts, etc.
6875
lldb::TargetSP m_target;
6976
llvm::StringRef m_expr;

lldb/include/lldb/ValueObject/DILParser.h

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLDB_VALUEOBJECT_DILPARSER_H
1111

1212
#include "lldb/Target/ExecutionContextScope.h"
13+
#include "lldb/Target/StackFrame.h"
1314
#include "lldb/Utility/DiagnosticsRendering.h"
1415
#include "lldb/Utility/Status.h"
1516
#include "lldb/ValueObject/DILAST.h"
@@ -31,6 +32,9 @@ enum class ErrorCode : unsigned char {
3132
kUnknown,
3233
};
3334

35+
llvm::Expected<lldb::TypeSystemSP>
36+
DILGetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx);
37+
3438
// The following is modeled on class OptionParseError.
3539
class DILDiagnosticError
3640
: public llvm::ErrorInfo<DILDiagnosticError, DiagnosticError> {
@@ -55,6 +59,61 @@ class DILDiagnosticError
5559

5660
std::string message() const override { return m_detail.rendered; }
5761
};
62+
/// TypeDeclaration builds information about the literal type definition as
63+
/// type is being parsed. It doesn't perform semantic analysis for non-basic
64+
/// types -- e.g. "char&&&" is a valid type declaration.
65+
/// NOTE: CV qualifiers are ignored.
66+
class TypeDeclaration {
67+
public:
68+
enum class TypeSpecifier {
69+
kBool,
70+
kChar,
71+
kDouble,
72+
kFloat,
73+
kInt,
74+
kLong,
75+
kLongDouble,
76+
kLongLong,
77+
kShort,
78+
kUnknown,
79+
kVoid,
80+
};
81+
82+
enum class SignSpecifier {
83+
kUnknown,
84+
kSigned,
85+
kUnsigned,
86+
};
87+
88+
bool IsEmpty() const { return !m_is_builtin && !m_is_user_type; }
89+
90+
lldb::BasicType GetBasicType() const;
91+
92+
public:
93+
// Indicates user-defined typename (e.g. "MyClass", "MyTmpl<int>").
94+
std::string m_user_typename;
95+
96+
// Basic type specifier ("void", "char", "intr", "float", "long long", etc.).
97+
TypeSpecifier m_type_specifier = TypeSpecifier::kUnknown;
98+
99+
// Signedness specifier ("signed", "unsigned").
100+
SignSpecifier m_sign_specifier = SignSpecifier::kUnknown;
101+
102+
// Does the type declaration includes "int" specifier?
103+
// This is different than `type_specifier_` and is used to detect "int"
104+
// duplication for types that can be combined with "int" specifier (e.g.
105+
// "short int", "long int").
106+
bool m_has_int_specifier = false;
107+
108+
// Indicates whether there was an error during parsing.
109+
bool m_has_error = false;
110+
111+
// Indicates whether this declaration describes a builtin type.
112+
bool m_is_builtin = false;
113+
114+
// Indicates whether this declaration describes a user type.
115+
bool m_is_user_type = false;
116+
}; // class TypeDeclaration
58117

59118
/// Pure recursive descent parser for C++ like expressions.
60119
/// EBNF grammar for the parser is described in lldb/docs/dil-expr-lang.ebnf
@@ -100,10 +159,22 @@ class DILParser {
100159
ASTNodeUP ParseIntegerLiteral();
101160
ASTNodeUP ParseFloatingPointLiteral();
102161

162+
ASTNodeUP ParseCastExpression();
163+
std::optional<CompilerType> ParseTypeId(bool must_be_type_id = false);
164+
void ParseTypeSpecifierSeq(TypeDeclaration *type_decl);
165+
bool ParseTypeSpecifier(TypeDeclaration *type_decl);
166+
std::string ParseTypeName();
167+
CompilerType ResolveTypeDeclarators(CompilerType type,
168+
const std::vector<Token> &ptr_operators);
169+
bool IsSimpleTypeSpecifierKeyword(Token token) const;
170+
bool HandleSimpleTypeSpecifier(TypeDeclaration *type_decl);
171+
103172
void BailOut(const std::string &error, uint32_t loc, uint16_t err_len);
104173

105174
void Expect(Token::Kind kind);
106175

176+
void ExpectOneOf(std::vector<Token::Kind> kinds_vec);
177+
107178
void TentativeParsingRollback(uint32_t saved_idx) {
108179
if (m_error)
109180
llvm::consumeError(std::move(m_error));
@@ -132,4 +203,66 @@ class DILParser {
132203

133204
} // namespace lldb_private::dil
134205

206+
namespace llvm {
207+
template <>
208+
struct format_provider<lldb_private::dil::TypeDeclaration::TypeSpecifier> {
209+
static void format(const lldb_private::dil::TypeDeclaration::TypeSpecifier &t,
210+
raw_ostream &OS, llvm::StringRef Options) {
211+
switch (t) {
212+
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kVoid:
213+
OS << "void";
214+
break;
215+
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kBool:
216+
OS << "bool";
217+
break;
218+
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kChar:
219+
OS << "char";
220+
break;
221+
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kInt:
222+
OS << "int";
223+
break;
224+
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kFloat:
225+
OS << "float";
226+
break;
227+
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kShort:
228+
OS << "short";
229+
break;
230+
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kLong:
231+
OS << "long";
232+
break;
233+
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kLongLong:
234+
OS << "long long";
235+
break;
236+
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kDouble:
237+
OS << "double";
238+
break;
239+
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kLongDouble:
240+
OS << "long double";
241+
break;
242+
default:
243+
OS << "invalid type specifier";
244+
break;
245+
}
246+
}
247+
};
248+
249+
template <>
250+
struct format_provider<lldb_private::dil::TypeDeclaration::SignSpecifier> {
251+
static void format(const lldb_private::dil::TypeDeclaration::SignSpecifier &t,
252+
raw_ostream &OS, llvm::StringRef Options) {
253+
switch (t) {
254+
case lldb_private::dil::TypeDeclaration::SignSpecifier::kSigned:
255+
OS << "signed";
256+
break;
257+
case lldb_private::dil::TypeDeclaration::SignSpecifier::kUnsigned:
258+
OS << "unsigned";
259+
break;
260+
default:
261+
OS << "invalid sign specifier";
262+
break;
263+
}
264+
}
265+
};
266+
} // namespace llvm
267+
135268
#endif // LLDB_VALUEOBJECT_DILPARSER_H

lldb/source/ValueObject/DILAST.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,8 @@ llvm::Expected<lldb::ValueObjectSP> FloatLiteralNode::Accept(Visitor *v) const {
4646
return v->Visit(this);
4747
}
4848

49+
llvm::Expected<lldb::ValueObjectSP> CStyleCastNode::Accept(Visitor *v) const {
50+
return v->Visit(this);
51+
}
52+
4953
} // namespace lldb_private::dil

0 commit comments

Comments
 (0)