pub enum ExprKind {
Show 18 variants
Error,
Const(ConstId),
Str(StrId),
Decl(DeclId),
Member {
base: ExprId,
field: u32,
},
Subscript {
base: ExprId,
index: ExprId,
},
Call {
callee: ExprId,
args: ExprList,
},
Unary {
op: UnaryOp,
operand: ExprId,
},
Binary {
op: BinaryOp,
lhs: ExprId,
rhs: ExprId,
},
Assign {
op: Option<BinaryOp>,
computation: TypeId,
lhs: ExprId,
rhs: ExprId,
},
Cond {
cond: ExprId,
then: ExprId,
otherwise: ExprId,
},
Comma {
lhs: ExprId,
rhs: ExprId,
},
Cast(ExprId),
Convert {
kind: Conversion,
operand: ExprId,
},
CompoundLiteral(DeclId),
StmtExpr(StmtId),
LabelAddr(LabelId),
VaArg {
list: ExprId,
},
}Expand description
What an expression is.
Variants§
Error
A node that was already the subject of a diagnostic.
Poisoned, in the sense of spec/06-lexer-and-parser.md section 6.8: nothing is reported
about one of these, which is what stops one bad declaration becoming forty bad uses.
Const(ConstId)
A constant, in the value table. Every constant that could be folded already has been.
Str(StrId)
A string literal, which is an array of characters with static storage duration.
Decl(DeclId)
A use of a declared object or function.
Member
base.field or, after the pointer has been dereferenced, base->field.
Fields
Subscript
base[index], with the pointer operand first however it was written.
Kept as a subscript rather than rewritten into *(base + index) because the rewriting
has exactly one home, which is the walk to the IR, and because a diagnostic about a
subscript should talk about a subscript.
Fields
Call
callee(args), with the arguments already converted to the parameter types.
Fields
Unary
A prefix or postfix operator on one operand.
Binary
A binary operator on two operands of the same type, except for the shifts and the pointer arithmetic, where the two sides legitimately differ.
Assign
lhs = rhs, or a compound assignment with the operator kept as written.
Fields
computation: TypeIdThe type the operation is performed in, which is the node’s own type for a plain assignment and for most compound ones.
It is here because a op= b is not a = a op b with the conversions left out, and
the difference is not academic: in int i = 5; i /= 0.5; the division happens in
double and the answer is ten, and a compiler that converts the right side to int
first divides by zero. The left side is an lvalue and cannot carry a conversion node
of its own, so the type it is read into is written here instead, which is what clang
calls the computation type and for the same reason.
Cond
cond ? then : otherwise, with both arms already converted to the common type.
Fields
Comma
lhs, rhs, whose value is the right side and whose left side is evaluated and dropped.
Cast(ExprId)
A cast the program wrote. The type is the node’s type.
Convert
A conversion the language performed. The type is the node’s type.
Fields
kind: ConversionWhich conversion, so that a reader and the verifier can both tell what happened rather than comparing the two types and guessing.
CompoundLiteral(DeclId)
(T){ ... }, which is an unnamed object with an initializer and not a conversion.
StmtExpr(StmtId)
({ ... }), GNU’s statement expression, whose value is its last expression statement.
LabelAddr(LabelId)
&&label, GNU’s label address.
VaArg
va_arg(list, T), which reads the next argument and moves the list on.
The type it fetches is the node’s own type, so there is nothing else to hold. It is a node rather than a call because what it becomes is the target’s own sequence of loads and not a function anything links against.