authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2019-04-20 22:43:53+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-04-29 21:30:19-04:00
log77383f968dde1e0d5d98865db8f560691d5f2afe
treea89e9016107532754a28a70b26625156a5d6cbc6
parentb1a61a6d51919cb8d5d87c53d495406491c53ebf

translate-c: Emit @ptrCast + @alignPtr sequence

Avoid producing Zig code that doesn't compile due to mismatched alignments between pointers. Always emit a @alignOf instead of hardcoding the alignment value returned by LLVM for portability sake of the generated code.

4 files changed, 82 insertions(+), 25 deletions(-)

src/translate_c.cpp+37-24
...@@ -121,6 +121,7 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const ZigClangStmt *s...@@ -121,6 +121,7 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const ZigClangStmt *s
121 TransScope **out_node_scope);121 TransScope **out_node_scope);
122static TransScope *trans_stmt(Context *c, TransScope *scope, const ZigClangStmt *stmt, AstNode **out_node);122static TransScope *trans_stmt(Context *c, TransScope *scope, const ZigClangStmt *stmt, AstNode **out_node);
123static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const ZigClangExpr *expr, TransLRValue lrval);123static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const ZigClangExpr *expr, TransLRValue lrval);
124static AstNode *trans_type(Context *c, const ZigClangType *ty, ZigClangSourceLocation source_loc);
124static AstNode *trans_qual_type(Context *c, ZigClangQualType qt, ZigClangSourceLocation source_loc);125static AstNode *trans_qual_type(Context *c, ZigClangQualType qt, ZigClangSourceLocation source_loc);
125static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope,126static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope,
126 const ZigClangExpr *expr, TransLRValue lrval);127 const ZigClangExpr *expr, TransLRValue lrval);
...@@ -575,13 +576,6 @@ static bool is_c_void_type(AstNode *node) {...@@ -575,13 +576,6 @@ static bool is_c_void_type(AstNode *node) {
575 return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void"));576 return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void"));
576}577}
577578
578static bool expr_types_equal(Context *c, const ZigClangExpr *expr1, const ZigClangExpr *expr2) {
579 ZigClangQualType t1 = get_expr_qual_type(c, expr1);
580 ZigClangQualType t2 = get_expr_qual_type(c, expr2);
581
582 return ZigClangQualType_eq(t1, t2);
583}
584
585static bool qual_type_is_ptr(ZigClangQualType qt) {579static bool qual_type_is_ptr(ZigClangQualType qt) {
586 const ZigClangType *ty = qual_type_canon(qt);580 const ZigClangType *ty = qual_type_canon(qt);
587 return ZigClangType_getTypeClass(ty) == ZigClangType_Pointer;581 return ZigClangType_getTypeClass(ty) == ZigClangType_Pointer;
...@@ -593,8 +587,7 @@ static const clang::FunctionProtoType *qual_type_get_fn_proto(ZigClangQualType q...@@ -593,8 +587,7 @@ static const clang::FunctionProtoType *qual_type_get_fn_proto(ZigClangQualType q
593587
594 if (ZigClangType_getTypeClass(ty) == ZigClangType_Pointer) {588 if (ZigClangType_getTypeClass(ty) == ZigClangType_Pointer) {
595 *is_ptr = true;589 *is_ptr = true;
596 const clang::PointerType *pointer_ty = reinterpret_cast<const clang::PointerType*>(ty);590 ZigClangQualType child_qt = ZigClangType_getPointeeType(ty);
597 ZigClangQualType child_qt = bitcast(pointer_ty->getPointeeType());
598 ty = ZigClangQualType_getTypePtr(child_qt);591 ty = ZigClangQualType_getTypePtr(child_qt);
599 }592 }
600593
...@@ -705,6 +698,36 @@ static bool qual_type_child_is_fn_proto(ZigClangQualType qt) {...@@ -705,6 +698,36 @@ static bool qual_type_child_is_fn_proto(ZigClangQualType qt) {
705 return false;698 return false;
706}699}
707700
701static AstNode* trans_c_ptr_cast(Context *c, ZigClangSourceLocation source_location, ZigClangQualType dest_type,
702 ZigClangQualType src_type, AstNode *expr)
703{
704 const ZigClangType *ty = ZigClangQualType_getTypePtr(dest_type);
705 const ZigClangQualType child_type = ZigClangType_getPointeeType(ty);
706
707 AstNode *dest_type_node = trans_type(c, ty, source_location);
708 AstNode *child_type_node = trans_qual_type(c, child_type, source_location);
709
710 // Implicit downcasting from higher to lower alignment values is forbidden,
711 // use @alignCast to side-step this problem
712 AstNode *ptrcast_node = trans_create_node_builtin_fn_call_str(c, "ptrCast");
713 ptrcast_node->data.fn_call_expr.params.append(dest_type_node);
714
715 if (ZigClangType_isVoidType(qual_type_canon(child_type))) {
716 // void has 1-byte alignment
717 ptrcast_node->data.fn_call_expr.params.append(expr);
718 } else {
719 AstNode *alignof_node = trans_create_node_builtin_fn_call_str(c, "alignOf");
720 alignof_node->data.fn_call_expr.params.append(child_type_node);
721 AstNode *aligncast_node = trans_create_node_builtin_fn_call_str(c, "alignCast");
722 aligncast_node->data.fn_call_expr.params.append(alignof_node);
723 aligncast_node->data.fn_call_expr.params.append(expr);
724
725 ptrcast_node->data.fn_call_expr.params.append(aligncast_node);
726 }
727
728 return ptrcast_node;
729}
730
708static AstNode* trans_c_cast(Context *c, ZigClangSourceLocation source_location, ZigClangQualType dest_type,731static AstNode* trans_c_cast(Context *c, ZigClangSourceLocation source_location, ZigClangQualType dest_type,
709 ZigClangQualType src_type, AstNode *expr)732 ZigClangQualType src_type, AstNode *expr)
710{733{
...@@ -719,10 +742,7 @@ static AstNode* trans_c_cast(Context *c, ZigClangSourceLocation source_location,...@@ -719,10 +742,7 @@ static AstNode* trans_c_cast(Context *c, ZigClangSourceLocation source_location,
719 return expr;742 return expr;
720 }743 }
721 if (qual_type_is_ptr(dest_type) && qual_type_is_ptr(src_type)) {744 if (qual_type_is_ptr(dest_type) && qual_type_is_ptr(src_type)) {
722 AstNode *ptr_cast_node = trans_create_node_builtin_fn_call_str(c, "ptrCast");745 return trans_c_ptr_cast(c, source_location, dest_type, src_type, expr);
723 ptr_cast_node->data.fn_call_expr.params.append(trans_qual_type(c, dest_type, source_location));
724 ptr_cast_node->data.fn_call_expr.params.append(expr);
725 return ptr_cast_node;
726 }746 }
727 // TODO: maybe widen to increase size747 // TODO: maybe widen to increase size
728 // TODO: maybe bitcast to change sign748 // TODO: maybe bitcast to change sign
...@@ -980,8 +1000,7 @@ static AstNode *trans_type(Context *c, const ZigClangType *ty, ZigClangSourceLoc...@@ -980,8 +1000,7 @@ static AstNode *trans_type(Context *c, const ZigClangType *ty, ZigClangSourceLoc
980 }1000 }
981 case ZigClangType_Pointer:1001 case ZigClangType_Pointer:
982 {1002 {
983 const clang::PointerType *pointer_ty = reinterpret_cast<const clang::PointerType*>(ty);1003 ZigClangQualType child_qt = ZigClangType_getPointeeType(ty);
984 ZigClangQualType child_qt = bitcast(pointer_ty->getPointeeType());
985 AstNode *child_node = trans_qual_type(c, child_qt, source_loc);1004 AstNode *child_node = trans_qual_type(c, child_qt, source_loc);
986 if (child_node == nullptr) {1005 if (child_node == nullptr) {
987 emit_warning(c, source_loc, "pointer to unsupported type");1006 emit_warning(c, source_loc, "pointer to unsupported type");
...@@ -1889,16 +1908,10 @@ static AstNode *trans_implicit_cast_expr(Context *c, ResultUsed result_used, Tra...@@ -1889,16 +1908,10 @@ static AstNode *trans_implicit_cast_expr(Context *c, ResultUsed result_used, Tra
1889 if (target_node == nullptr)1908 if (target_node == nullptr)
1890 return nullptr;1909 return nullptr;
18911910
1892 if (expr_types_equal(c, (const ZigClangExpr *)stmt, bitcast(stmt->getSubExpr()))) {1911 const ZigClangQualType dest_type = get_expr_qual_type(c, bitcast(stmt));
1893 return target_node;1912 const ZigClangQualType src_type = get_expr_qual_type(c, bitcast(stmt->getSubExpr()));
1894 }
18951913
1896 AstNode *dest_type_node = get_expr_type(c, (const ZigClangExpr *)stmt);1914 return trans_c_cast(c, bitcast(stmt->getBeginLoc()), dest_type, src_type, target_node);
1897
1898 AstNode *node = trans_create_node_builtin_fn_call_str(c, "ptrCast");
1899 node->data.fn_call_expr.params.append(dest_type_node);
1900 node->data.fn_call_expr.params.append(target_node);
1901 return maybe_suppress_result(c, result_used, node);
1902 }1915 }
1903 case ZigClangCK_NullToPointer:1916 case ZigClangCK_NullToPointer:
1904 return trans_create_node_unsigned(c, 0);1917 return trans_create_node_unsigned(c, 0);
src/zig_clang.cpp+9
...@@ -870,6 +870,10 @@ ZigClangQualType ZigClangASTContext_getPointerType(const ZigClangASTContext* sel...@@ -870,6 +870,10 @@ ZigClangQualType ZigClangASTContext_getPointerType(const ZigClangASTContext* sel
870 return bitcast(reinterpret_cast<const clang::ASTContext *>(self)->getPointerType(bitcast(T)));870 return bitcast(reinterpret_cast<const clang::ASTContext *>(self)->getPointerType(bitcast(T)));
871}871}
872872
873unsigned ZigClangASTContext_getTypeAlign(const ZigClangASTContext* self, ZigClangQualType T) {
874 return reinterpret_cast<const clang::ASTContext *>(self)->getTypeAlign(bitcast(T));
875}
876
873ZigClangASTContext *ZigClangASTUnit_getASTContext(ZigClangASTUnit *self) {877ZigClangASTContext *ZigClangASTUnit_getASTContext(ZigClangASTUnit *self) {
874 clang::ASTContext *result = &reinterpret_cast<clang::ASTUnit *>(self)->getASTContext();878 clang::ASTContext *result = &reinterpret_cast<clang::ASTUnit *>(self)->getASTContext();
875 return reinterpret_cast<ZigClangASTContext *>(result);879 return reinterpret_cast<ZigClangASTContext *>(result);
...@@ -1030,6 +1034,11 @@ ZigClangTypeClass ZigClangType_getTypeClass(const ZigClangType *self) {...@@ -1030,6 +1034,11 @@ ZigClangTypeClass ZigClangType_getTypeClass(const ZigClangType *self) {
1030 return (ZigClangTypeClass)tc;1034 return (ZigClangTypeClass)tc;
1031}1035}
10321036
1037ZigClangQualType ZigClangType_getPointeeType(const ZigClangType *self) {
1038 auto casted = reinterpret_cast<const clang::Type *>(self);
1039 return bitcast(casted->getPointeeType());
1040}
1041
1033bool ZigClangType_isVoidType(const ZigClangType *self) {1042bool ZigClangType_isVoidType(const ZigClangType *self) {
1034 auto casted = reinterpret_cast<const clang::Type *>(self);1043 auto casted = reinterpret_cast<const clang::Type *>(self);
1035 return casted->isVoidType();1044 return casted->isVoidType();
src/zig_clang.h+1
...@@ -543,6 +543,7 @@ ZIG_EXTERN_C bool ZigClangQualType_isVolatileQualified(struct ZigClangQualType);...@@ -543,6 +543,7 @@ ZIG_EXTERN_C bool ZigClangQualType_isVolatileQualified(struct ZigClangQualType);
543ZIG_EXTERN_C bool ZigClangQualType_isRestrictQualified(struct ZigClangQualType);543ZIG_EXTERN_C bool ZigClangQualType_isRestrictQualified(struct ZigClangQualType);
544544
545ZIG_EXTERN_C enum ZigClangTypeClass ZigClangType_getTypeClass(const struct ZigClangType *self);545ZIG_EXTERN_C enum ZigClangTypeClass ZigClangType_getTypeClass(const struct ZigClangType *self);
546ZIG_EXTERN_C ZigClangQualType ZigClangType_getPointeeType(const ZigClangType *self);
546ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self);547ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self);
547ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self);548ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self);
548549
test/translate_c.zig+35-1
...@@ -1334,7 +1334,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1334,7 +1334,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1334 \\}1334 \\}
1335 ,1335 ,
1336 \\fn ptrcast(a: [*c]c_int) [*c]f32 {1336 \\fn ptrcast(a: [*c]c_int) [*c]f32 {
1337 \\ return @ptrCast([*c]f32, a);1337 \\ return @ptrCast([*c]f32, @alignCast(@alignOf(f32), a));
1338 \\}1338 \\}
1339 );1339 );
13401340
...@@ -1608,6 +1608,40 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1608,6 +1608,40 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1608 \\}1608 \\}
1609 );1609 );
16101610
1611 cases.addC("pointer conversion with different alignment",
1612 \\void test_ptr_cast() {
1613 \\ void *p;
1614 \\ {
1615 \\ char *to_char = (char *)p;
1616 \\ short *to_short = (short *)p;
1617 \\ int *to_int = (int *)p;
1618 \\ long long *to_longlong = (long long *)p;
1619 \\ }
1620 \\ {
1621 \\ char *to_char = p;
1622 \\ short *to_short = p;
1623 \\ int *to_int = p;
1624 \\ long long *to_longlong = p;
1625 \\ }
1626 \\}
1627 ,
1628 \\pub export fn test_ptr_cast() void {
1629 \\ var p: ?*c_void = undefined;
1630 \\ {
1631 \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p));
1632 \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p));
1633 \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p));
1634 \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p));
1635 \\ }
1636 \\ {
1637 \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p));
1638 \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p));
1639 \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p));
1640 \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p));
1641 \\ }
1642 \\}
1643 );
1644
1611 // cases.add("empty array with initializer",1645 // cases.add("empty array with initializer",
1612 // "int a[4] = {};"1646 // "int a[4] = {};"
1613 // ,1647 // ,