authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-26 20:05:55-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-26 20:05:55-05:00
log671183fa9a0be28851002d07ad7ddf0d3bd29b46
tree16e3e7ece2d4d626df86750c4337243a4c230e78
parent93fac5f257a80c2ca0abd30aedbeae300f6460f8

translate-c: support pointer casting

also avoid some unnecessary casts

2 files changed, 97 insertions(+), 54 deletions(-)

src/translate_c.cpp+79-39
...@@ -440,6 +440,10 @@ static AstNode *trans_create_node_apint(Context *c, const llvm::APSInt &aps_int)...@@ -440,6 +440,10 @@ static AstNode *trans_create_node_apint(Context *c, const llvm::APSInt &aps_int)
440440
441}441}
442442
443static const Type *qual_type_canon(QualType qt) {
444 return qt.getCanonicalType().getTypePtr();
445}
446
443static QualType get_expr_qual_type(Context *c, const Expr *expr) {447static QualType get_expr_qual_type(Context *c, const Expr *expr) {
444 // String literals in C are `char *` but they should really be `const char *`.448 // String literals in C are `char *` but they should really be `const char *`.
445 if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) {449 if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) {
...@@ -462,10 +466,7 @@ static AstNode *get_expr_type(Context *c, const Expr *expr) {...@@ -462,10 +466,7 @@ static AstNode *get_expr_type(Context *c, const Expr *expr) {
462 return trans_qual_type(c, get_expr_qual_type(c, expr), expr->getLocStart());466 return trans_qual_type(c, get_expr_qual_type(c, expr), expr->getLocStart());
463}467}
464468
465static bool expr_types_equal(Context *c, const Expr *expr1, const Expr *expr2) {469static bool qual_types_equal(QualType t1, QualType t2) {
466 QualType t1 = get_expr_qual_type(c, expr1);
467 QualType t2 = get_expr_qual_type(c, expr2);
468
469 if (t1.isConstQualified() != t2.isConstQualified()) {470 if (t1.isConstQualified() != t2.isConstQualified()) {
470 return false;471 return false;
471 }472 }
...@@ -482,26 +483,27 @@ static bool is_c_void_type(AstNode *node) {...@@ -482,26 +483,27 @@ static bool is_c_void_type(AstNode *node) {
482 return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void"));483 return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void"));
483}484}
484485
485static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location, const QualType &qt, AstNode *expr) {486static bool expr_types_equal(Context *c, const Expr *expr1, const Expr *expr2) {
486 // TODO: maybe widen to increase size487 QualType t1 = get_expr_qual_type(c, expr1);
487 // TODO: maybe bitcast to change sign488 QualType t2 = get_expr_qual_type(c, expr2);
488 // TODO: maybe truncate to reduce size489
489 return trans_create_node_fn_call_1(c, trans_qual_type(c, qt, source_location), expr);490 return qual_types_equal(t1, t2);
490}491}
491492
492static bool qual_type_is_fn_ptr(Context *c, const QualType &qt) {493static bool qual_type_is_ptr(QualType qt) {
493 const Type *ty = qt.getTypePtr();494 const Type *ty = qual_type_canon(qt);
495 return ty->getTypeClass() == Type::Pointer;
496}
497
498static bool qual_type_is_fn_ptr(Context *c, QualType qt) {
499 const Type *ty = qual_type_canon(qt);
494 if (ty->getTypeClass() != Type::Pointer) {500 if (ty->getTypeClass() != Type::Pointer) {
495 return false;501 return false;
496 }502 }
497 const PointerType *pointer_ty = static_cast<const PointerType*>(ty);503 const PointerType *pointer_ty = static_cast<const PointerType*>(ty);
498 QualType child_qt = pointer_ty->getPointeeType();504 QualType child_qt = pointer_ty->getPointeeType();
499 const Type *child_ty = child_qt.getTypePtr();505 const Type *child_ty = child_qt.getTypePtr();
500 if (child_ty->getTypeClass() != Type::Paren) {506 return child_ty->getTypeClass() == Type::FunctionProto;
501 return false;
502 }
503 const ParenType *paren_ty = static_cast<const ParenType *>(child_ty);
504 return paren_ty->getInnerType().getTypePtr()->getTypeClass() == Type::FunctionProto;
505}507}
506508
507static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const SourceLocation &source_loc) {509static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const SourceLocation &source_loc) {
...@@ -594,17 +596,26 @@ static bool qual_type_child_is_fn_proto(const QualType &qt) {...@@ -594,17 +596,26 @@ static bool qual_type_child_is_fn_proto(const QualType &qt) {
594 return false;596 return false;
595}597}
596598
597static QualType resolve_any_typedef(Context *c, QualType qt) {599static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location, QualType dest_type,
598 const Type * ty = qt.getTypePtr();600 QualType src_type, AstNode *expr)
599 if (ty->getTypeClass() != Type::Typedef)601{
600 return qt;602 if (qual_types_equal(dest_type, src_type)) {
601 const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty);603 return expr;
602 const TypedefNameDecl *typedef_decl = typedef_ty->getDecl();604 }
603 return typedef_decl->getUnderlyingType();605 if (qual_type_is_ptr(dest_type) && qual_type_is_ptr(src_type)) {
606 AstNode *ptr_cast_node = trans_create_node_builtin_fn_call_str(c, "ptrCast");
607 ptr_cast_node->data.fn_call_expr.params.append(trans_qual_type(c, dest_type, source_location));
608 ptr_cast_node->data.fn_call_expr.params.append(expr);
609 return ptr_cast_node;
610 }
611 // TODO: maybe widen to increase size
612 // TODO: maybe bitcast to change sign
613 // TODO: maybe truncate to reduce size
614 return trans_create_node_fn_call_1(c, trans_qual_type(c, dest_type, source_location), expr);
604}615}
605616
606static bool c_is_signed_integer(Context *c, QualType qt) {617static bool c_is_signed_integer(Context *c, QualType qt) {
607 const Type *c_type = resolve_any_typedef(c, qt).getTypePtr();618 const Type *c_type = qual_type_canon(qt);
608 if (c_type->getTypeClass() != Type::Builtin)619 if (c_type->getTypeClass() != Type::Builtin)
609 return false;620 return false;
610 const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type);621 const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type);
...@@ -623,7 +634,7 @@ static bool c_is_signed_integer(Context *c, QualType qt) {...@@ -623,7 +634,7 @@ static bool c_is_signed_integer(Context *c, QualType qt) {
623}634}
624635
625static bool c_is_unsigned_integer(Context *c, QualType qt) {636static bool c_is_unsigned_integer(Context *c, QualType qt) {
626 const Type *c_type = resolve_any_typedef(c, qt).getTypePtr();637 const Type *c_type = qual_type_canon(qt);
627 if (c_type->getTypeClass() != Type::Builtin)638 if (c_type->getTypeClass() != Type::Builtin)
628 return false;639 return false;
629 const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type);640 const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type);
...@@ -891,6 +902,11 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou...@@ -891,6 +902,11 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
891 return nullptr;902 return nullptr;
892 }903 }
893 // convert c_void to actual void (only for return type)904 // convert c_void to actual void (only for return type)
905 // we do want to look at the AstNode instead of QualType, because
906 // if they do something like:
907 // typedef Foo void;
908 // void foo(void) -> Foo;
909 // we want to keep the return type AST node.
894 if (is_c_void_type(proto_node->data.fn_proto.return_type)) {910 if (is_c_void_type(proto_node->data.fn_proto.return_type)) {
895 proto_node->data.fn_proto.return_type = nullptr;911 proto_node->data.fn_proto.return_type = nullptr;
896 }912 }
...@@ -1317,19 +1333,28 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result...@@ -1317,19 +1333,28 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
1317 if (rhs == nullptr) return nullptr;1333 if (rhs == nullptr) return nullptr;
1318 AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);1334 AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
13191335
1336 // operation_type(*_ref)
1337 AstNode *operation_type_cast = trans_c_cast(c, rhs_location,
1338 stmt->getComputationLHSType(),
1339 stmt->getLHS()->getType(),
1340 trans_create_node_prefix_op(c, PrefixOpDereference,
1341 trans_create_node_symbol(c, tmp_var_name)));
1342
1343 // result_type(... >> u5(rhs))
1344 AstNode *result_type_cast = trans_c_cast(c, rhs_location,
1345 stmt->getComputationResultType(),
1346 stmt->getComputationLHSType(),
1347 trans_create_node_bin_op(c,
1348 operation_type_cast,
1349 bin_op,
1350 coerced_rhs));
1351
1352 // *_ref = ...
1320 AstNode *assign_statement = trans_create_node_bin_op(c,1353 AstNode *assign_statement = trans_create_node_bin_op(c,
1321 trans_create_node_prefix_op(c, PrefixOpDereference,1354 trans_create_node_prefix_op(c, PrefixOpDereference,
1322 trans_create_node_symbol(c, tmp_var_name)),1355 trans_create_node_symbol(c, tmp_var_name)),
1323 BinOpTypeAssign,1356 BinOpTypeAssign, result_type_cast);
1324 trans_c_cast(c, rhs_location,1357
1325 stmt->getComputationResultType(),
1326 trans_create_node_bin_op(c,
1327 trans_c_cast(c, rhs_location,
1328 stmt->getComputationLHSType(),
1329 trans_create_node_prefix_op(c, PrefixOpDereference,
1330 trans_create_node_symbol(c, tmp_var_name))),
1331 bin_op,
1332 coerced_rhs)));
1333 child_scope->node->data.block.statements.append(assign_statement);1358 child_scope->node->data.block.statements.append(assign_statement);
13341359
1335 if (result_used == ResultUsedYes) {1360 if (result_used == ResultUsedYes) {
...@@ -1474,7 +1499,8 @@ static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const Im...@@ -1474,7 +1499,8 @@ static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const Im
1474 AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue);1499 AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue);
1475 if (target_node == nullptr)1500 if (target_node == nullptr)
1476 return nullptr;1501 return nullptr;
1477 return trans_c_cast(c, stmt->getExprLoc(), stmt->getType(), target_node);1502 return trans_c_cast(c, stmt->getExprLoc(), stmt->getType(),
1503 stmt->getSubExpr()->getType(), target_node);
1478 }1504 }
1479 case CK_FunctionToPointerDecay:1505 case CK_FunctionToPointerDecay:
1480 case CK_ArrayToPointerDecay:1506 case CK_ArrayToPointerDecay:
...@@ -2177,9 +2203,23 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *...@@ -2177,9 +2203,23 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *
2177 if (callee_raw_node == nullptr)2203 if (callee_raw_node == nullptr)
2178 return nullptr;2204 return nullptr;
21792205
2180 AstNode *callee_node;2206 AstNode *callee_node = nullptr;
2181 if (qual_type_is_fn_ptr(c, stmt->getCallee()->getType())) {2207 if (qual_type_is_fn_ptr(c, stmt->getCallee()->getType())) {
2182 callee_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, callee_raw_node);2208 if (stmt->getCallee()->getStmtClass() == Stmt::ImplicitCastExprClass) {
2209 const ImplicitCastExpr *implicit_cast = static_cast<const ImplicitCastExpr *>(stmt->getCallee());
2210 if (implicit_cast->getCastKind() == CK_FunctionToPointerDecay) {
2211 if (implicit_cast->getSubExpr()->getStmtClass() == Stmt::DeclRefExprClass) {
2212 const DeclRefExpr *decl_ref = static_cast<const DeclRefExpr *>(implicit_cast->getSubExpr());
2213 const Decl *decl = decl_ref->getFoundDecl();
2214 if (decl->getKind() == Decl::Function) {
2215 callee_node = callee_raw_node;
2216 }
2217 }
2218 }
2219 }
2220 if (callee_node == nullptr) {
2221 callee_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, callee_raw_node);
2222 }
2183 } else {2223 } else {
2184 callee_node = callee_raw_node;2224 callee_node = callee_raw_node;
2185 }2225 }
...@@ -2237,7 +2277,7 @@ static AstNode *trans_c_style_cast_expr(Context *c, ResultUsed result_used, Tran...@@ -2237,7 +2277,7 @@ static AstNode *trans_c_style_cast_expr(Context *c, ResultUsed result_used, Tran
2237 if (sub_expr_node == nullptr)2277 if (sub_expr_node == nullptr)
2238 return nullptr;2278 return nullptr;
22392279
2240 return trans_c_cast(c, stmt->getLocStart(), stmt->getType(), sub_expr_node);2280 return trans_c_cast(c, stmt->getLocStart(), stmt->getType(), stmt->getSubExpr()->getType(), sub_expr_node);
2241}2281}
22422282
2243static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, TransScope *scope,2283static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, TransScope *scope,
test/translate_c.zig+18-15
...@@ -677,12 +677,12 @@ pub fn addCases(cases: &tests.TranslateCContext) {...@@ -677,12 +677,12 @@ pub fn addCases(cases: &tests.TranslateCContext) {
677 \\ };677 \\ };
678 \\ a >>= @import("std").math.Log2Int(c_int)({678 \\ a >>= @import("std").math.Log2Int(c_int)({
679 \\ const _ref = &a;679 \\ const _ref = &a;
680 \\ (*_ref) = c_int(c_int(*_ref) >> @import("std").math.Log2Int(c_int)(1));680 \\ (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_int)(1));
681 \\ *_ref681 \\ *_ref
682 \\ });682 \\ });
683 \\ a <<= @import("std").math.Log2Int(c_int)({683 \\ a <<= @import("std").math.Log2Int(c_int)({
684 \\ const _ref = &a;684 \\ const _ref = &a;
685 \\ (*_ref) = c_int(c_int(*_ref) << @import("std").math.Log2Int(c_int)(1));685 \\ (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_int)(1));
686 \\ *_ref686 \\ *_ref
687 \\ });687 \\ });
688 \\}688 \\}
...@@ -735,12 +735,12 @@ pub fn addCases(cases: &tests.TranslateCContext) {...@@ -735,12 +735,12 @@ pub fn addCases(cases: &tests.TranslateCContext) {
735 \\ };735 \\ };
736 \\ a >>= @import("std").math.Log2Int(c_uint)({736 \\ a >>= @import("std").math.Log2Int(c_uint)({
737 \\ const _ref = &a;737 \\ const _ref = &a;
738 \\ (*_ref) = c_uint(c_uint(*_ref) >> @import("std").math.Log2Int(c_uint)(1));738 \\ (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_uint)(1));
739 \\ *_ref739 \\ *_ref
740 \\ });740 \\ });
741 \\ a <<= @import("std").math.Log2Int(c_uint)({741 \\ a <<= @import("std").math.Log2Int(c_uint)({
742 \\ const _ref = &a;742 \\ const _ref = &a;
743 \\ (*_ref) = c_uint(c_uint(*_ref) << @import("std").math.Log2Int(c_uint)(1));743 \\ (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_uint)(1));
744 \\ *_ref744 \\ *_ref
745 \\ });745 \\ });
746 \\}746 \\}
...@@ -878,17 +878,21 @@ pub fn addCases(cases: &tests.TranslateCContext) {...@@ -878,17 +878,21 @@ pub fn addCases(cases: &tests.TranslateCContext) {
878878
879 cases.addC("deref function pointer",879 cases.addC("deref function pointer",
880 \\void foo(void) {}880 \\void foo(void) {}
881 \\void baz(void) {}
881 \\void bar(void) {882 \\void bar(void) {
882 \\ void(*f)(void) = foo;883 \\ void(*f)(void) = foo;
883 \\ f();884 \\ f();
884 \\ (*(f))();885 \\ (*(f))();
886 \\ baz();
885 \\}887 \\}
886 ,888 ,
887 \\export fn foo() {}889 \\export fn foo() {}
890 \\export fn baz() {}
888 \\export fn bar() {891 \\export fn bar() {
889 \\ var f: ?extern fn() = foo;892 \\ var f: ?extern fn() = foo;
890 \\ (??f)();893 \\ (??f)();
891 \\ (??f)();894 \\ (??f)();
895 \\ baz();
892 \\}896 \\}
893 );897 );
894898
...@@ -1100,15 +1104,14 @@ pub fn addCases(cases: &tests.TranslateCContext) {...@@ -1100,15 +1104,14 @@ pub fn addCases(cases: &tests.TranslateCContext) {
1100 \\ return x;1104 \\ return x;
1101 \\}1105 \\}
1102 );1106 );
1103}
1104
11051107
11061108 cases.add("pointer casting",
1107// TODO1109 \\float *ptrcast(int *a) {
1108//float *ptrcast(int *a) {1110 \\ return (float *)a;
1109// return (float *)a;1111 \\}
1110//}1112 ,
1111// should translate to1113 \\fn ptrcast(a: ?&c_int) -> ?&f32 {
1112// fn ptrcast(a: ?&c_int) -> ?&f32 {1114 \\ return @ptrCast(?&f32, a);
1113// return @ptrCast(?&f32, a);1115 \\}
1114// }1116 );
1117}