mirror of
https://github.com/ziglang/zig.git
synced 2026-02-14 05:20:34 +00:00
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.
This commit is contained in:
parent
b1a61a6d51
commit
77383f968d
@ -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);
|
||||
@ -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;
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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)
|
||||
{
|
||||
@ -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
|
||||
@ -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");
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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));
|
||||
\\}
|
||||
);
|
||||
|
||||
@ -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] = {};"
|
||||
// ,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user