Merge remote-tracking branch 'upstream/master' into llvm6

master
Ryan Saunderson 2017-11-14 07:00:27 -06:00
commit 371e578151
6 changed files with 731 additions and 167 deletions

View File

@ -625,7 +625,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
fprintf(ar->f, "@");
}
AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
bool grouped = (fn_ref_node->type != NodeTypeBinOpExpr);
bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr);
render_node_extra(ar, fn_ref_node, grouped);
fprintf(ar->f, "(");
for (size_t i = 0; i < node->data.fn_call_expr.params.length; i += 1) {

View File

@ -350,6 +350,21 @@ static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location,
return trans_create_node_fn_call_1(c, trans_qual_type(c, qt, source_location), expr);
}
static bool qual_type_is_fn_ptr(Context *c, const QualType &qt) {
const Type *ty = qt.getTypePtr();
if (ty->getTypeClass() != Type::Pointer) {
return false;
}
const PointerType *pointer_ty = static_cast<const PointerType*>(ty);
QualType child_qt = pointer_ty->getPointeeType();
const Type *child_ty = child_qt.getTypePtr();
if (child_ty->getTypeClass() != Type::Paren) {
return false;
}
const ParenType *paren_ty = static_cast<const ParenType *>(child_ty);
return paren_ty->getInnerType().getTypePtr()->getTypeClass() == Type::FunctionProto;
}
static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const SourceLocation &source_loc) {
const Type *ty = qt.getTypePtr();
switch (ty->getTypeClass()) {
@ -990,6 +1005,21 @@ static AstNode *trans_create_assign(Context *c, bool result_used, AstNode *block
}
}
static AstNode *trans_create_shift_op(Context *c, AstNode *block, QualType result_type, Expr *lhs_expr, BinOpType bin_op, Expr *rhs_expr) {
const SourceLocation &rhs_location = rhs_expr->getLocStart();
AstNode *rhs_type = qual_type_to_log2_int_ref(c, result_type, rhs_location);
// lhs >> u5(rh)
AstNode *lhs = trans_expr(c, true, block, lhs_expr, TransLValue);
if (lhs == nullptr) return nullptr;
AstNode *rhs = trans_expr(c, true, block, rhs_expr, TransRValue);
if (rhs == nullptr) return nullptr;
AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
return trans_create_node_bin_op(c, lhs, bin_op, coerced_rhs);
}
static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *block, BinaryOperator *stmt) {
switch (stmt->getOpcode()) {
case BO_PtrMemD:
@ -1022,7 +1052,7 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
// unsigned/float division uses the operator
return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeMod, stmt->getRHS());
} else {
// signed integer division uses @divTrunc
// signed integer division uses @rem
AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "rem");
AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
if (lhs == nullptr) return nullptr;
@ -1041,11 +1071,9 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeSubWrap : BinOpTypeSub,
stmt->getRHS());
case BO_Shl:
emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Shl");
return nullptr;
return trans_create_shift_op(c, block, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftLeft, stmt->getRHS());
case BO_Shr:
emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Shr");
return nullptr;
return trans_create_shift_op(c, block, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftRight, stmt->getRHS());
case BO_LT:
return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpLessThan, stmt->getRHS());
case BO_GT:
@ -1071,49 +1099,167 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS());
case BO_Assign:
return trans_create_assign(c, result_used, block, stmt->getLHS(), stmt->getRHS());
case BO_MulAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_MulAssign");
return nullptr;
case BO_DivAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_DivAssign");
return nullptr;
case BO_RemAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_RemAssign");
return nullptr;
case BO_AddAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_AddAssign");
return nullptr;
case BO_SubAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_SubAssign");
return nullptr;
case BO_ShlAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_ShlAssign");
return nullptr;
case BO_ShrAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_ShrAssign");
return nullptr;
case BO_AndAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_AndAssign");
return nullptr;
case BO_XorAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_XorAssign");
return nullptr;
case BO_OrAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_OrAssign");
return nullptr;
case BO_Comma:
emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Comma");
return nullptr;
{
block = trans_create_node(c, NodeTypeBlock);
AstNode *lhs = trans_expr(c, false, block, stmt->getLHS(), TransRValue);
if (lhs == nullptr) return nullptr;
block->data.block.statements.append(maybe_suppress_result(c, false, lhs));
AstNode *rhs = trans_expr(c, result_used, block, stmt->getRHS(), TransRValue);
if (rhs == nullptr) return nullptr;
block->data.block.statements.append(maybe_suppress_result(c, result_used, rhs));
block->data.block.last_statement_is_result_expression = true;
return block;
}
case BO_MulAssign:
case BO_DivAssign:
case BO_RemAssign:
case BO_AddAssign:
case BO_SubAssign:
case BO_ShlAssign:
case BO_ShrAssign:
case BO_AndAssign:
case BO_XorAssign:
case BO_OrAssign:
zig_unreachable();
}
zig_unreachable();
}
static AstNode *trans_create_compound_assign_shift(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) {
const SourceLocation &rhs_location = stmt->getRHS()->getLocStart();
AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location);
bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr();
if (!use_intermediate_casts && !result_used) {
// simple common case, where the C and Zig are identical:
// lhs >>= rhs
AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
if (lhs == nullptr) return nullptr;
AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue);
if (rhs == nullptr) return nullptr;
AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
return trans_create_node_bin_op(c, lhs, assign_op, coerced_rhs);
} else {
// need more complexity. worst case, this looks like this:
// c: lhs >>= rhs
// zig: {
// zig: const _ref = &lhs;
// zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs));
// zig: *_ref
// zig: }
// where u5 is the appropriate type
AstNode *child_block = trans_create_node(c, NodeTypeBlock);
// const _ref = &lhs;
AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue);
if (lhs == nullptr) return nullptr;
AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs);
// TODO: avoid name collisions with generated variable names
Buf* tmp_var_name = buf_create_from_str("_ref");
AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs);
child_block->data.block.statements.append(tmp_var_decl);
// *_ref = result_type(operation_type(*_ref) >> u5(rhs));
AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue);
if (rhs == nullptr) return nullptr;
AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
AstNode *assign_statement = trans_create_node_bin_op(c,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, tmp_var_name)),
BinOpTypeAssign,
trans_c_cast(c, rhs_location,
stmt->getComputationResultType(),
trans_create_node_bin_op(c,
trans_c_cast(c, rhs_location,
stmt->getComputationLHSType(),
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, tmp_var_name))),
bin_op,
coerced_rhs)));
child_block->data.block.statements.append(assign_statement);
if (result_used) {
// *_ref
child_block->data.block.statements.append(
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, tmp_var_name)));
child_block->data.block.last_statement_is_result_expression = true;
}
return child_block;
}
}
static AstNode *trans_create_compound_assign(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) {
if (!result_used) {
// simple common case, where the C and Zig are identical:
// lhs += rhs
AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
if (lhs == nullptr) return nullptr;
AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue);
if (rhs == nullptr) return nullptr;
return trans_create_node_bin_op(c, lhs, assign_op, rhs);
} else {
// need more complexity. worst case, this looks like this:
// c: lhs += rhs
// zig: {
// zig: const _ref = &lhs;
// zig: *_ref = *_ref + rhs;
// zig: *_ref
// zig: }
AstNode *child_block = trans_create_node(c, NodeTypeBlock);
// const _ref = &lhs;
AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue);
if (lhs == nullptr) return nullptr;
AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs);
// TODO: avoid name collisions with generated variable names
Buf* tmp_var_name = buf_create_from_str("_ref");
AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs);
child_block->data.block.statements.append(tmp_var_decl);
// *_ref = *_ref + rhs;
AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue);
if (rhs == nullptr) return nullptr;
AstNode *assign_statement = trans_create_node_bin_op(c,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, tmp_var_name)),
BinOpTypeAssign,
trans_create_node_bin_op(c,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, tmp_var_name)),
bin_op,
rhs));
child_block->data.block.statements.append(assign_statement);
// *_ref
child_block->data.block.statements.append(
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, tmp_var_name)));
child_block->data.block.last_statement_is_result_expression = true;
return child_block;
}
}
static AstNode *trans_compound_assign_operator(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt) {
switch (stmt->getOpcode()) {
case BO_MulAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_MulAssign");
return nullptr;
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignTimesWrap, BinOpTypeMultWrap);
else
return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignTimes, BinOpTypeMult);
case BO_DivAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_DivAssign");
return nullptr;
@ -1121,95 +1267,25 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_RemAssign");
return nullptr;
case BO_AddAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_AddAssign");
return nullptr;
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignPlusWrap, BinOpTypeAddWrap);
else
return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignPlus, BinOpTypeAdd);
case BO_SubAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_SubAssign");
return nullptr;
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignMinusWrap, BinOpTypeSubWrap);
else
return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignMinus, BinOpTypeSub);
case BO_ShlAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_ShlAssign");
return nullptr;
case BO_ShrAssign: {
BinOpType bin_op = BinOpTypeBitShiftRight;
const SourceLocation &rhs_location = stmt->getRHS()->getLocStart();
AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location);
bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr();
if (!use_intermediate_casts && !result_used) {
// simple common case, where the C and Zig are identical:
// lhs >>= rh* s
AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
if (lhs == nullptr) return nullptr;
AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue);
if (rhs == nullptr) return nullptr;
AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
return trans_create_node_bin_op(c, lhs, BinOpTypeAssignBitShiftRight, coerced_rhs);
} else {
// need more complexity. worst case, this looks like this:
// c: lhs >>= rhs
// zig: {
// zig: const _ref = &lhs;
// zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs));
// zig: *_ref
// zig: }
// where u5 is the appropriate type
// TODO: avoid mess when we don't need the assignment value for chained assignments or anything.
AstNode *child_block = trans_create_node(c, NodeTypeBlock);
// const _ref = &lhs;
AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue);
if (lhs == nullptr) return nullptr;
AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs);
// TODO: avoid name collisions with generated variable names
Buf* tmp_var_name = buf_create_from_str("_ref");
AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs);
child_block->data.block.statements.append(tmp_var_decl);
// *_ref = result_type(operation_type(*_ref) >> u5(rhs));
AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue);
if (rhs == nullptr) return nullptr;
AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
AstNode *assign_statement = trans_create_node_bin_op(c,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, tmp_var_name)),
BinOpTypeAssign,
trans_c_cast(c, rhs_location,
stmt->getComputationResultType(),
trans_create_node_bin_op(c,
trans_c_cast(c, rhs_location,
stmt->getComputationLHSType(),
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, tmp_var_name))),
bin_op,
coerced_rhs)));
child_block->data.block.statements.append(assign_statement);
if (result_used) {
// *_ref
child_block->data.block.statements.append(
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, tmp_var_name)));
child_block->data.block.last_statement_is_result_expression = true;
}
return child_block;
}
}
return trans_create_compound_assign_shift(c, result_used, block, stmt, BinOpTypeAssignBitShiftLeft, BinOpTypeBitShiftLeft);
case BO_ShrAssign:
return trans_create_compound_assign_shift(c, result_used, block, stmt, BinOpTypeAssignBitShiftRight, BinOpTypeBitShiftRight);
case BO_AndAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_AndAssign");
return nullptr;
return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitAnd, BinOpTypeBinAnd);
case BO_XorAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_XorAssign");
return nullptr;
return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitXor, BinOpTypeBinXor);
case BO_OrAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_OrAssign");
return nullptr;
return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitOr, BinOpTypeBinOr);
case BO_PtrMemD:
case BO_PtrMemI:
case BO_Assign:
@ -1232,7 +1308,7 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast
case BO_LAnd:
case BO_LOr:
case BO_Comma:
zig_panic("compound assign expected to be handled by binary operator");
zig_unreachable();
}
zig_unreachable();
@ -1270,6 +1346,8 @@ static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCas
node->data.fn_call_expr.params.append(target_node);
return node;
}
case CK_NullToPointer:
return trans_create_node(c, NodeTypeNullLiteral);
case CK_Dependent:
emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent");
return nullptr;
@ -1294,9 +1372,6 @@ static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCas
case CK_ToUnion:
emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ToUnion");
return nullptr;
case CK_NullToPointer:
emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NullToPointer");
return nullptr;
case CK_NullToMemberPointer:
emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NullToMemberPointer");
return nullptr;
@ -1442,38 +1517,72 @@ static AstNode *trans_decl_ref_expr(Context *c, DeclRefExpr *stmt, TransLRValue
return trans_create_node_symbol(c, symbol_name);
}
static AstNode *trans_create_post_crement(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt, BinOpType assign_op) {
Expr *op_expr = stmt->getSubExpr();
if (!result_used) {
// common case
// c: expr++
// zig: expr += 1
return trans_create_node_bin_op(c,
trans_expr(c, true, block, op_expr, TransLValue),
assign_op,
trans_create_node_unsigned(c, 1));
} else {
// worst case
// c: expr++
// zig: {
// zig: const _ref = &expr;
// zig: const _tmp = *_ref;
// zig: *_ref += 1;
// zig: _tmp
// zig: }
AstNode *child_block = trans_create_node(c, NodeTypeBlock);
// const _ref = &expr;
AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue);
if (expr == nullptr) return nullptr;
AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr);
// TODO: avoid name collisions with generated variable names
Buf* ref_var_name = buf_create_from_str("_ref");
AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr);
child_block->data.block.statements.append(ref_var_decl);
// const _tmp = *_ref;
Buf* tmp_var_name = buf_create_from_str("_tmp");
AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, ref_var_name)));
child_block->data.block.statements.append(tmp_var_decl);
// *_ref += 1;
AstNode *assign_statement = trans_create_node_bin_op(c,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, ref_var_name)),
assign_op,
trans_create_node_unsigned(c, 1));
child_block->data.block.statements.append(assign_statement);
// _tmp
child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
child_block->data.block.last_statement_is_result_expression = true;
return child_block;
}
}
static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) {
switch (stmt->getOpcode()) {
case UO_PostInc: {
Expr *op_expr = stmt->getSubExpr();
BinOpType bin_op = qual_type_has_wrapping_overflow(c, op_expr->getType())
? BinOpTypeAssignPlusWrap
: BinOpTypeAssignPlus;
if (!result_used) {
// common case
// c: expr++
// zig: expr += 1
return trans_create_node_bin_op(c,
trans_expr(c, true, block, op_expr, TransLValue),
bin_op,
trans_create_node_unsigned(c, 1));
} else {
// worst case
// c: expr++
// zig: {
// zig: const _ref = &expr;
// zig: const _tmp = *_ref;
// zig: *_ref += 1;
// zig: _tmp
// zig: }
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostInc with result_used");
return nullptr;
}
}
case UO_PostInc:
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlusWrap);
else
return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlus);
case UO_PostDec:
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostDec");
return nullptr;
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinusWrap);
else
return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinus);
case UO_PreInc:
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreInc");
return nullptr;
@ -1484,8 +1593,14 @@ static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *bloc
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_AddrOf");
return nullptr;
case UO_Deref:
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Deref");
return nullptr;
{
bool is_fn_ptr = qual_type_is_fn_ptr(c, stmt->getSubExpr()->getType());
AstNode *value_node = trans_expr(c, result_used, block, stmt->getSubExpr(), TransRValue);
if (is_fn_ptr)
return value_node;
AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node);
return trans_create_node_prefix_op(c, PrefixOpDereference, unwrapped);
}
case UO_Plus:
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Plus");
return nullptr;
@ -1828,10 +1943,20 @@ static AstNode *trans_if_statement(Context *c, AstNode *block, IfStmt *stmt) {
static AstNode *trans_call_expr(Context *c, bool result_used, AstNode *block, CallExpr *stmt) {
AstNode *node = trans_create_node(c, NodeTypeFnCallExpr);
node->data.fn_call_expr.fn_ref_expr = trans_expr(c, true, block, stmt->getCallee(), TransRValue);
if (node->data.fn_call_expr.fn_ref_expr == nullptr)
AstNode *callee_raw_node = trans_expr(c, true, block, stmt->getCallee(), TransRValue);
if (callee_raw_node == nullptr)
return nullptr;
AstNode *callee_node;
if (qual_type_is_fn_ptr(c, stmt->getCallee()->getType())) {
callee_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, callee_raw_node);
} else {
callee_node = callee_raw_node;
}
node->data.fn_call_expr.fn_ref_expr = callee_node;
unsigned num_args = stmt->getNumArgs();
Expr **args = stmt->getArgs();
for (unsigned i = 0; i < num_args; i += 1) {
@ -1896,6 +2021,59 @@ static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, AstNode *block,
return node;
}
static AstNode *trans_do_loop(Context *c, AstNode *block, DoStmt *stmt) {
stmt->getBody();
stmt->getCond();
AstNode *while_node = trans_create_node(c, NodeTypeWhileExpr);
AstNode *true_node = trans_create_node(c, NodeTypeBoolLiteral);
true_node->data.bool_literal.value = true;
while_node->data.while_expr.condition = true_node;
AstNode *body_node;
if (stmt->getBody()->getStmtClass() == Stmt::CompoundStmtClass) {
// there's already a block in C, so we'll append our condition to it.
// c: do {
// c: a;
// c: b;
// c: } while(c);
// zig: while (true) {
// zig: a;
// zig: b;
// zig: if (!cond) break;
// zig: }
body_node = trans_stmt(c, false, block, stmt->getBody(), TransRValue);
if (body_node == nullptr) return nullptr;
assert(body_node->type == NodeTypeBlock);
} else {
// the C statement is without a block, so we need to create a block to contain it.
// c: do
// c: a;
// c: while(c);
// zig: while (true) {
// zig: a;
// zig: if (!cond) break;
// zig: }
body_node = trans_create_node(c, NodeTypeBlock);
AstNode *child_statement = trans_stmt(c, false, body_node, stmt->getBody(), TransRValue);
if (child_statement == nullptr) return nullptr;
body_node->data.block.statements.append(child_statement);
}
// if (!cond) break;
AstNode *condition_node = trans_expr(c, true, body_node, stmt->getCond(), TransRValue);
if (condition_node == nullptr) return nullptr;
AstNode *terminator_node = trans_create_node(c, NodeTypeIfBoolExpr);
terminator_node->data.if_bool_expr.condition = trans_create_node_prefix_op(c, PrefixOpBoolNot, condition_node);
terminator_node->data.if_bool_expr.then_block = trans_create_node(c, NodeTypeBreak);
body_node->data.block.statements.append(terminator_node);
while_node->data.while_expr.body = body_node;
return while_node;
}
static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrvalue) {
Stmt::StmtClass sc = stmt->getStmtClass();
switch (sc) {
@ -1935,6 +2113,8 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s
return trans_c_style_cast_expr(c, result_used, block, (CStyleCastExpr *)stmt, lrvalue);
case Stmt::UnaryExprOrTypeTraitExprClass:
return trans_unary_expr_or_type_trait_expr(c, block, (UnaryExprOrTypeTraitExpr *)stmt);
case Stmt::DoStmtClass:
return trans_do_loop(c, block, (DoStmt *)stmt);
case Stmt::CaseStmtClass:
emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass");
return nullptr;
@ -1980,9 +2160,6 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s
case Stmt::CoroutineBodyStmtClass:
emit_warning(c, stmt->getLocStart(), "TODO handle C CoroutineBodyStmtClass");
return nullptr;
case Stmt::DoStmtClass:
emit_warning(c, stmt->getLocStart(), "TODO handle C DoStmtClass");
return nullptr;
case Stmt::BinaryConditionalOperatorClass:
emit_warning(c, stmt->getLocStart(), "TODO handle C BinaryConditionalOperatorClass");
return nullptr;

View File

@ -5,8 +5,14 @@ const Rand = std.rand.Rand;
const assert = std.debug.assert;
const mem = std.mem;
const os = std.os;
const builtin = @import("builtin");
test "write a file, read it, then delete it" {
if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
// TODO get this test passing
// https://github.com/zig-lang/zig/issues/537
return;
}
var data: [1024]u8 = undefined;
var rng = Rand.init(1234);
rng.fillBytes(data[0..]);

View File

@ -328,6 +328,45 @@ pub const TIOCGPKT = 0x80045438;
pub const TIOCGPTLCK = 0x80045439;
pub const TIOCGEXCL = 0x80045440;
pub const EPOLL_CTL_ADD = 1;
pub const EPOLL_CTL_DEL = 2;
pub const EPOLL_CTL_MOD = 3;
pub const EPOLLIN = 0x001;
pub const EPOLLPRI = 0x002;
pub const EPOLLOUT = 0x004;
pub const EPOLLRDNORM = 0x040;
pub const EPOLLRDBAND = 0x080;
pub const EPOLLWRNORM = 0x100;
pub const EPOLLWRBAND = 0x200;
pub const EPOLLMSG = 0x400;
pub const EPOLLERR = 0x008;
pub const EPOLLHUP = 0x010;
pub const EPOLLRDHUP = 0x2000;
pub const EPOLLEXCLUSIVE = (u32(1) << 28);
pub const EPOLLWAKEUP = (u32(1) << 29);
pub const EPOLLONESHOT = (u32(1) << 30);
pub const EPOLLET = (u32(1) << 31);
pub const CLOCK_REALTIME = 0;
pub const CLOCK_MONOTONIC = 1;
pub const CLOCK_PROCESS_CPUTIME_ID = 2;
pub const CLOCK_THREAD_CPUTIME_ID = 3;
pub const CLOCK_MONOTONIC_RAW = 4;
pub const CLOCK_REALTIME_COARSE = 5;
pub const CLOCK_MONOTONIC_COARSE = 6;
pub const CLOCK_BOOTTIME = 7;
pub const CLOCK_REALTIME_ALARM = 8;
pub const CLOCK_BOOTTIME_ALARM = 9;
pub const CLOCK_SGI_CYCLE = 10;
pub const CLOCK_TAI = 11;
pub const TFD_NONBLOCK = O_NONBLOCK;
pub const TFD_CLOEXEC = O_CLOEXEC;
pub const TFD_TIMER_ABSTIME = 1;
pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
fn unsigned(s: i32) -> u32 { @bitCast(u32, s) }
fn signed(s: u32) -> i32 { @bitCast(i32, s) }
pub fn WEXITSTATUS(s: i32) -> i32 { signed((unsigned(s) & 0xff00) >> 8) }
@ -734,3 +773,47 @@ pub const timespec = arch.timespec;
pub fn fstat(fd: i32, stat_buf: &Stat) -> usize {
arch.syscall2(arch.SYS_fstat, usize(fd), @ptrToInt(stat_buf))
}
pub const epoll_data = u64;
pub const epoll_event = extern struct {
events: u32,
data: epoll_data
};
pub fn epoll_create() -> usize {
arch.syscall1(arch.SYS_epoll_create, usize(1))
}
pub fn epoll_ctl(epoll_fd: i32, op: i32, fd: i32, ev: &epoll_event) -> usize {
arch.syscall4(arch.SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev))
}
pub fn epoll_wait(epoll_fd: i32, events: &epoll_event, maxevents: i32, timeout: i32) -> usize {
arch.syscall4(arch.SYS_epoll_wait, usize(epoll_fd), @ptrToInt(events), usize(maxevents), usize(timeout))
}
pub fn timerfd_create(clockid: i32, flags: u32) -> usize {
arch.syscall2(arch.SYS_timerfd_create, usize(clockid), usize(flags))
}
pub const itimerspec = extern struct {
it_interval: timespec,
it_value: timespec
};
pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) -> usize {
arch.syscall2(arch.SYS_timerfd_gettime, usize(fd), @ptrToInt(curr_value))
}
pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_value: ?&itimerspec) -> usize {
arch.syscall4(arch.SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value))
}
test "import linux_test" {
// TODO lazy analysis should prevent this test from being compiled on windows, but
// it is still compiled on windows
if (builtin.os == builtin.Os.linux) {
_ = @import("linux_test.zig");
}
}

38
std/os/linux_test.zig Normal file
View File

@ -0,0 +1,38 @@
const std = @import("std");
const linux = std.os.linux;
const assert = std.debug.assert;
test "timer" {
const epoll_fd = linux.epoll_create();
var err = linux.getErrno(epoll_fd);
assert(err == 0);
const timer_fd = linux.timerfd_create(linux.CLOCK_MONOTONIC, 0);
assert(linux.getErrno(timer_fd) == 0);
const time_interval = linux.timespec {
.tv_sec = 0,
.tv_nsec = 2000000
};
const new_time = linux.itimerspec {
.it_interval = time_interval,
.it_value = time_interval
};
err = linux.timerfd_settime(i32(timer_fd), 0, &new_time, null);
assert(err == 0);
var event = linux.epoll_event {
.events = linux.EPOLLIN | linux.EPOLLOUT | linux.EPOLLET,
.data = 0
};
err = linux.epoll_ctl(i32(epoll_fd), linux.EPOLL_CTL_ADD, i32(timer_fd), &event);
assert(err == 0);
const events_one: linux.epoll_event = undefined;
var events = []linux.epoll_event{events_one} ** 8;
err = linux.epoll_wait(i32(epoll_fd), &events[0], 8, -1);
}

View File

@ -203,13 +203,13 @@ pub fn addCases(cases: &tests.ParseCContext) {
\\pub extern var fn_ptr: ?extern fn();
,
\\pub inline fn foo() {
\\ ??fn_ptr()
\\ (??fn_ptr)()
\\}
,
\\pub extern var fn_ptr2: ?extern fn(c_int, f32) -> u8;
,
\\pub inline fn bar(arg0: c_int, arg1: f32) -> u8 {
\\ ??fn_ptr2(arg0, arg1)
\\ (??fn_ptr2)(arg0, arg1)
\\}
);
@ -596,8 +596,268 @@ pub fn addCases(cases: &tests.ParseCContext) {
\\ return @sizeOf(c_int);
\\}
);
}
cases.addC("null pointer implicit cast",
\\int* foo(void) {
\\ return 0;
\\}
,
\\export fn foo() -> ?&c_int {
\\ return null;
\\}
);
cases.addC("comma operator",
\\int foo(void) {
\\ return 1, 2;
\\}
,
\\export fn foo() -> c_int {
\\ return {
\\ _ = 1;
\\ 2
\\ };
\\}
);
cases.addC("bitshift",
\\int foo(void) {
\\ return (1 << 2) >> 1;
\\}
,
\\export fn foo() -> c_int {
\\ return (1 << @import("std").math.Log2Int(c_int)(2)) >> @import("std").math.Log2Int(c_int)(1);
\\}
);
cases.addC("compound assignment operators",
\\void foo(void) {
\\ int a = 0;
\\ a += (a += 1);
\\ a -= (a -= 1);
\\ a *= (a *= 1);
\\ a &= (a &= 1);
\\ a |= (a |= 1);
\\ a ^= (a ^= 1);
\\ a >>= (a >>= 1);
\\ a <<= (a <<= 1);
\\}
,
\\export fn foo() {
\\ var a: c_int = 0;
\\ a += {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) + 1);
\\ *_ref
\\ };
\\ a -= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) - 1);
\\ *_ref
\\ };
\\ a *= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) * 1);
\\ *_ref
\\ };
\\ a &= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) & 1);
\\ *_ref
\\ };
\\ a |= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) | 1);
\\ *_ref
\\ };
\\ a ^= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) ^ 1);
\\ *_ref
\\ };
\\ a >>= @import("std").math.Log2Int(c_int)({
\\ const _ref = &a;
\\ (*_ref) = c_int(c_int(*_ref) >> @import("std").math.Log2Int(c_int)(1));
\\ *_ref
\\ });
\\ a <<= @import("std").math.Log2Int(c_int)({
\\ const _ref = &a;
\\ (*_ref) = c_int(c_int(*_ref) << @import("std").math.Log2Int(c_int)(1));
\\ *_ref
\\ });
\\}
);
cases.addC("compound assignment operators unsigned",
\\void foo(void) {
\\ unsigned a = 0;
\\ a += (a += 1);
\\ a -= (a -= 1);
\\ a *= (a *= 1);
\\ a &= (a &= 1);
\\ a |= (a |= 1);
\\ a ^= (a ^= 1);
\\ a >>= (a >>= 1);
\\ a <<= (a <<= 1);
\\}
,
\\export fn foo() {
\\ var a: c_uint = c_uint(0);
\\ a +%= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) +% c_uint(1));
\\ *_ref
\\ };
\\ a -%= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) -% c_uint(1));
\\ *_ref
\\ };
\\ a *%= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) *% c_uint(1));
\\ *_ref
\\ };
\\ a &= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) & c_uint(1));
\\ *_ref
\\ };
\\ a |= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) | c_uint(1));
\\ *_ref
\\ };
\\ a ^= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) ^ c_uint(1));
\\ *_ref
\\ };
\\ a >>= @import("std").math.Log2Int(c_uint)({
\\ const _ref = &a;
\\ (*_ref) = c_uint(c_uint(*_ref) >> @import("std").math.Log2Int(c_uint)(1));
\\ *_ref
\\ });
\\ a <<= @import("std").math.Log2Int(c_uint)({
\\ const _ref = &a;
\\ (*_ref) = c_uint(c_uint(*_ref) << @import("std").math.Log2Int(c_uint)(1));
\\ *_ref
\\ });
\\}
);
cases.addC("duplicate typedef",
\\typedef long foo;
\\typedef int bar;
\\typedef long foo;
\\typedef int baz;
,
\\pub const foo = c_long;
\\pub const bar = c_int;
\\pub const baz = c_int;
);
cases.addC("post increment/decrement",
\\void foo(void) {
\\ int i = 0;
\\ unsigned u = 0;
\\ i++;
\\ i--;
\\ u++;
\\ u--;
\\ i = i++;
\\ i = i--;
\\ u = u++;
\\ u = u--;
\\}
,
\\export fn foo() {
\\ var i: c_int = 0;
\\ var u: c_uint = c_uint(0);
\\ i += 1;
\\ i -= 1;
\\ u +%= 1;
\\ u -%= 1;
\\ i = {
\\ const _ref = &i;
\\ const _tmp = *_ref;
\\ (*_ref) += 1;
\\ _tmp
\\ };
\\ i = {
\\ const _ref = &i;
\\ const _tmp = *_ref;
\\ (*_ref) -= 1;
\\ _tmp
\\ };
\\ u = {
\\ const _ref = &u;
\\ const _tmp = *_ref;
\\ (*_ref) +%= 1;
\\ _tmp
\\ };
\\ u = {
\\ const _ref = &u;
\\ const _tmp = *_ref;
\\ (*_ref) -%= 1;
\\ _tmp
\\ };
\\}
);
cases.addC("do loop",
\\void foo(void) {
\\ int a = 2;
\\ do {
\\ a--;
\\ } while (a != 0);
\\
\\ int b = 2;
\\ do
\\ b--;
\\ while (b != 0);
\\}
,
\\export fn foo() {
\\ var a: c_int = 2;
\\ while (true) {
\\ a -= 1;
\\ if (!(a != 0)) break;
\\ };
\\ var b: c_int = 2;
\\ while (true) {
\\ b -= 1;
\\ if (!(b != 0)) break;
\\ };
\\}
);
cases.addC("deref function pointer",
\\void foo(void) {}
\\void bar(void) {
\\ void(*f)(void) = foo;
\\ f();
\\ (*(f))();
\\}
,
\\export fn foo() {}
\\export fn bar() {
\\ var f: ?extern fn() = foo;
\\ (??f)();
\\ (??f)();
\\}
);
cases.addC("normal deref",
\\void foo(int *x) {
\\ *x = 1;
\\}
,
\\export fn foo(x: ?&c_int) {
\\ (*(??x)) = 1;
\\}
);
}