Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Translate c pointer alignment #2318

Merged
merged 1 commit into from
Apr 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 37 additions & 24 deletions src/translate_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const ZigClangStmt *s
TransScope **out_node_scope);
static TransScope *trans_stmt(Context *c, TransScope *scope, const ZigClangStmt *stmt, AstNode **out_node);
static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const ZigClangExpr *expr, TransLRValue lrval);
static AstNode *trans_type(Context *c, const ZigClangType *ty, ZigClangSourceLocation source_loc);
static AstNode *trans_qual_type(Context *c, ZigClangQualType qt, ZigClangSourceLocation source_loc);
static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope,
const ZigClangExpr *expr, TransLRValue lrval);
Expand Down Expand Up @@ -575,13 +576,6 @@ static bool is_c_void_type(AstNode *node) {
return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void"));
}

static bool expr_types_equal(Context *c, const ZigClangExpr *expr1, const ZigClangExpr *expr2) {
ZigClangQualType t1 = get_expr_qual_type(c, expr1);
ZigClangQualType t2 = get_expr_qual_type(c, expr2);

return ZigClangQualType_eq(t1, t2);
}

static bool qual_type_is_ptr(ZigClangQualType qt) {
const ZigClangType *ty = qual_type_canon(qt);
return ZigClangType_getTypeClass(ty) == ZigClangType_Pointer;
Expand All @@ -593,8 +587,7 @@ static const clang::FunctionProtoType *qual_type_get_fn_proto(ZigClangQualType q

if (ZigClangType_getTypeClass(ty) == ZigClangType_Pointer) {
*is_ptr = true;
const clang::PointerType *pointer_ty = reinterpret_cast<const clang::PointerType*>(ty);
ZigClangQualType child_qt = bitcast(pointer_ty->getPointeeType());
ZigClangQualType child_qt = ZigClangType_getPointeeType(ty);
ty = ZigClangQualType_getTypePtr(child_qt);
}

Expand Down Expand Up @@ -705,6 +698,36 @@ static bool qual_type_child_is_fn_proto(ZigClangQualType qt) {
return false;
}

static AstNode* trans_c_ptr_cast(Context *c, ZigClangSourceLocation source_location, ZigClangQualType dest_type,
ZigClangQualType src_type, AstNode *expr)
{
const ZigClangType *ty = ZigClangQualType_getTypePtr(dest_type);
const ZigClangQualType child_type = ZigClangType_getPointeeType(ty);

AstNode *dest_type_node = trans_type(c, ty, source_location);
AstNode *child_type_node = trans_qual_type(c, child_type, source_location);

// Implicit downcasting from higher to lower alignment values is forbidden,
// use @alignCast to side-step this problem
AstNode *ptrcast_node = trans_create_node_builtin_fn_call_str(c, "ptrCast");
ptrcast_node->data.fn_call_expr.params.append(dest_type_node);

if (ZigClangType_isVoidType(qual_type_canon(child_type))) {
// void has 1-byte alignment
ptrcast_node->data.fn_call_expr.params.append(expr);
} else {
AstNode *alignof_node = trans_create_node_builtin_fn_call_str(c, "alignOf");
alignof_node->data.fn_call_expr.params.append(child_type_node);
AstNode *aligncast_node = trans_create_node_builtin_fn_call_str(c, "alignCast");
aligncast_node->data.fn_call_expr.params.append(alignof_node);
aligncast_node->data.fn_call_expr.params.append(expr);

ptrcast_node->data.fn_call_expr.params.append(aligncast_node);
}

return ptrcast_node;
}

static AstNode* trans_c_cast(Context *c, ZigClangSourceLocation source_location, ZigClangQualType dest_type,
ZigClangQualType src_type, AstNode *expr)
{
Expand All @@ -719,10 +742,7 @@ static AstNode* trans_c_cast(Context *c, ZigClangSourceLocation source_location,
return expr;
}
if (qual_type_is_ptr(dest_type) && qual_type_is_ptr(src_type)) {
AstNode *ptr_cast_node = trans_create_node_builtin_fn_call_str(c, "ptrCast");
ptr_cast_node->data.fn_call_expr.params.append(trans_qual_type(c, dest_type, source_location));
ptr_cast_node->data.fn_call_expr.params.append(expr);
return ptr_cast_node;
return trans_c_ptr_cast(c, source_location, dest_type, src_type, expr);
}
// TODO: maybe widen to increase size
// TODO: maybe bitcast to change sign
Expand Down Expand Up @@ -980,8 +1000,7 @@ static AstNode *trans_type(Context *c, const ZigClangType *ty, ZigClangSourceLoc
}
case ZigClangType_Pointer:
{
const clang::PointerType *pointer_ty = reinterpret_cast<const clang::PointerType*>(ty);
ZigClangQualType child_qt = bitcast(pointer_ty->getPointeeType());
ZigClangQualType child_qt = ZigClangType_getPointeeType(ty);
AstNode *child_node = trans_qual_type(c, child_qt, source_loc);
if (child_node == nullptr) {
emit_warning(c, source_loc, "pointer to unsupported type");
Expand Down Expand Up @@ -1889,16 +1908,10 @@ static AstNode *trans_implicit_cast_expr(Context *c, ResultUsed result_used, Tra
if (target_node == nullptr)
return nullptr;

if (expr_types_equal(c, (const ZigClangExpr *)stmt, bitcast(stmt->getSubExpr()))) {
return target_node;
}
const ZigClangQualType dest_type = get_expr_qual_type(c, bitcast(stmt));
const ZigClangQualType src_type = get_expr_qual_type(c, bitcast(stmt->getSubExpr()));

AstNode *dest_type_node = get_expr_type(c, (const ZigClangExpr *)stmt);

AstNode *node = trans_create_node_builtin_fn_call_str(c, "ptrCast");
node->data.fn_call_expr.params.append(dest_type_node);
node->data.fn_call_expr.params.append(target_node);
return maybe_suppress_result(c, result_used, node);
return trans_c_cast(c, bitcast(stmt->getBeginLoc()), dest_type, src_type, target_node);
}
case ZigClangCK_NullToPointer:
return trans_create_node_unsigned(c, 0);
Expand Down
9 changes: 9 additions & 0 deletions src/zig_clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,10 @@ ZigClangQualType ZigClangASTContext_getPointerType(const ZigClangASTContext* sel
return bitcast(reinterpret_cast<const clang::ASTContext *>(self)->getPointerType(bitcast(T)));
}

unsigned ZigClangASTContext_getTypeAlign(const ZigClangASTContext* self, ZigClangQualType T) {
return reinterpret_cast<const clang::ASTContext *>(self)->getTypeAlign(bitcast(T));
}

ZigClangASTContext *ZigClangASTUnit_getASTContext(ZigClangASTUnit *self) {
clang::ASTContext *result = &reinterpret_cast<clang::ASTUnit *>(self)->getASTContext();
return reinterpret_cast<ZigClangASTContext *>(result);
Expand Down Expand Up @@ -1030,6 +1034,11 @@ ZigClangTypeClass ZigClangType_getTypeClass(const ZigClangType *self) {
return (ZigClangTypeClass)tc;
}

ZigClangQualType ZigClangType_getPointeeType(const ZigClangType *self) {
auto casted = reinterpret_cast<const clang::Type *>(self);
return bitcast(casted->getPointeeType());
}

bool ZigClangType_isVoidType(const ZigClangType *self) {
auto casted = reinterpret_cast<const clang::Type *>(self);
return casted->isVoidType();
Expand Down
1 change: 1 addition & 0 deletions src/zig_clang.h
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ ZIG_EXTERN_C bool ZigClangQualType_isVolatileQualified(struct ZigClangQualType);
ZIG_EXTERN_C bool ZigClangQualType_isRestrictQualified(struct ZigClangQualType);

ZIG_EXTERN_C enum ZigClangTypeClass ZigClangType_getTypeClass(const struct ZigClangType *self);
ZIG_EXTERN_C ZigClangQualType ZigClangType_getPointeeType(const ZigClangType *self);
ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self);
ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self);

Expand Down
36 changes: 35 additions & 1 deletion test/translate_c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1334,7 +1334,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
,
\\fn ptrcast(a: [*c]c_int) [*c]f32 {
\\ return @ptrCast([*c]f32, a);
\\ return @ptrCast([*c]f32, @alignCast(@alignOf(f32), a));
\\}
);

Expand Down Expand Up @@ -1608,6 +1608,40 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
);

cases.addC("pointer conversion with different alignment",
\\void test_ptr_cast() {
\\ void *p;
\\ {
\\ char *to_char = (char *)p;
\\ short *to_short = (short *)p;
\\ int *to_int = (int *)p;
\\ long long *to_longlong = (long long *)p;
\\ }
\\ {
\\ char *to_char = p;
\\ short *to_short = p;
\\ int *to_int = p;
\\ long long *to_longlong = p;
\\ }
\\}
,
\\pub export fn test_ptr_cast() void {
\\ var p: ?*c_void = undefined;
\\ {
\\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p));
\\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p));
\\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p));
\\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p));
\\ }
\\ {
\\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p));
\\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p));
\\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p));
\\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p));
\\ }
\\}
);

// cases.add("empty array with initializer",
// "int a[4] = {};"
// ,
Expand Down