translate-c: add limited OffsetOfExpr support
Add support for OffsetOfExpr that contain exactly 1 component, when that component
is a field.
For example, given:
```c
struct S {
float f;
double d;
};
struct T {
long l;
int i;
struct S s[10];
};
```
Then:
```c
offsetof(struct T, i) // supported
offsetof(struct T, s[2].d) // not supported currently
```
This commit is contained in:
committed by
Veikka Tuominen
parent
0423f0f7d8
commit
294ee1bbc9
@@ -432,6 +432,9 @@ pub const FieldDecl = opaque {
|
||||
|
||||
pub const getLocation = ZigClangFieldDecl_getLocation;
|
||||
extern fn ZigClangFieldDecl_getLocation(*const FieldDecl) SourceLocation;
|
||||
|
||||
pub const getParent = ZigClangFieldDecl_getParent;
|
||||
extern fn ZigClangFieldDecl_getParent(*const FieldDecl) ?*const RecordDecl;
|
||||
};
|
||||
|
||||
pub const FileID = opaque {};
|
||||
@@ -593,6 +596,34 @@ pub const TypeOfExprType = opaque {
|
||||
extern fn ZigClangTypeOfExprType_getUnderlyingExpr(*const TypeOfExprType) *const Expr;
|
||||
};
|
||||
|
||||
pub const OffsetOfNode = opaque {
|
||||
pub const getKind = ZigClangOffsetOfNode_getKind;
|
||||
extern fn ZigClangOffsetOfNode_getKind(*const OffsetOfNode) OffsetOfNode_Kind;
|
||||
|
||||
pub const getArrayExprIndex = ZigClangOffsetOfNode_getArrayExprIndex;
|
||||
extern fn ZigClangOffsetOfNode_getArrayExprIndex(*const OffsetOfNode) c_uint;
|
||||
|
||||
pub const getField = ZigClangOffsetOfNode_getField;
|
||||
extern fn ZigClangOffsetOfNode_getField(*const OffsetOfNode) *FieldDecl;
|
||||
};
|
||||
|
||||
pub const OffsetOfExpr = opaque {
|
||||
pub const getNumComponents = ZigClangOffsetOfExpr_getNumComponents;
|
||||
extern fn ZigClangOffsetOfExpr_getNumComponents(*const OffsetOfExpr) c_uint;
|
||||
|
||||
pub const getNumExpressions = ZigClangOffsetOfExpr_getNumExpressions;
|
||||
extern fn ZigClangOffsetOfExpr_getNumExpressions(*const OffsetOfExpr) c_uint;
|
||||
|
||||
pub const getIndexExpr = ZigClangOffsetOfExpr_getIndexExpr;
|
||||
extern fn ZigClangOffsetOfExpr_getIndexExpr(*const OffsetOfExpr, idx: c_uint) *const Expr;
|
||||
|
||||
pub const getComponent = ZigClangOffsetOfExpr_getComponent;
|
||||
extern fn ZigClangOffsetOfExpr_getComponent(*const OffsetOfExpr, idx: c_uint) *const OffsetOfNode;
|
||||
|
||||
pub const getBeginLoc = ZigClangOffsetOfExpr_getBeginLoc;
|
||||
extern fn ZigClangOffsetOfExpr_getBeginLoc(*const OffsetOfExpr) SourceLocation;
|
||||
};
|
||||
|
||||
pub const MemberExpr = opaque {
|
||||
pub const getBase = ZigClangMemberExpr_getBase;
|
||||
extern fn ZigClangMemberExpr_getBase(*const MemberExpr) *const Expr;
|
||||
@@ -1655,6 +1686,13 @@ pub const UnaryExprOrTypeTrait_Kind = extern enum {
|
||||
PreferredAlignOf,
|
||||
};
|
||||
|
||||
pub const OffsetOfNode_Kind = extern enum {
|
||||
Array,
|
||||
Field,
|
||||
Identifier,
|
||||
Base,
|
||||
};
|
||||
|
||||
pub const Stage2ErrorMsg = extern struct {
|
||||
filename_ptr: ?[*]const u8,
|
||||
filename_len: usize,
|
||||
|
||||
@@ -1069,12 +1069,64 @@ fn transStmt(
|
||||
const expr = try transExpr(c, scope, source_expr, .used);
|
||||
return maybeSuppressResult(c, scope, result_used, expr);
|
||||
},
|
||||
.OffsetOfExprClass => return transOffsetOfExpr(c, scope, @ptrCast(*const clang.OffsetOfExpr, stmt), result_used),
|
||||
else => {
|
||||
return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Translate a "simple" offsetof expression containing exactly one component,
|
||||
/// when that component is of kind .Field - e.g. offsetof(mytype, myfield)
|
||||
fn transSimpleOffsetOfExpr(
|
||||
c: *Context,
|
||||
scope: *Scope,
|
||||
expr: *const clang.OffsetOfExpr,
|
||||
) TransError!Node {
|
||||
assert(expr.getNumComponents() == 1);
|
||||
const component = expr.getComponent(0);
|
||||
if (component.getKind() == .Field) {
|
||||
const field_decl = component.getField();
|
||||
if (field_decl.getParent()) |record_decl| {
|
||||
if (c.decl_table.get(@ptrToInt(record_decl.getCanonicalDecl()))) |type_name| {
|
||||
const type_node = try Tag.type.create(c.arena, type_name);
|
||||
|
||||
var raw_field_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
|
||||
const quoted_field_name = try std.fmt.allocPrint(c.arena, "\"{s}\"", .{raw_field_name});
|
||||
const field_name_node = try Tag.string_literal.create(c.arena, quoted_field_name);
|
||||
|
||||
return Tag.byte_offset_of.create(c.arena, .{
|
||||
.lhs = type_node,
|
||||
.rhs = field_name_node,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "Failed to translate simple OffsetOfExpr", .{});
|
||||
}
|
||||
|
||||
fn transOffsetOfExpr(
|
||||
c: *Context,
|
||||
scope: *Scope,
|
||||
expr: *const clang.OffsetOfExpr,
|
||||
result_used: ResultUsed,
|
||||
) TransError!Node {
|
||||
if (expr.getNumComponents() == 1) {
|
||||
const offsetof_expr = try transSimpleOffsetOfExpr(c, scope, expr);
|
||||
return maybeSuppressResult(c, scope, result_used, offsetof_expr);
|
||||
}
|
||||
|
||||
// TODO implement OffsetOfExpr with more than 1 component
|
||||
// OffsetOfExpr API:
|
||||
// call expr.getComponent(idx) while idx < expr.getNumComponents()
|
||||
// component.getKind() will be either .Array or .Field (other kinds are C++-only)
|
||||
// if .Field, use component.getField() to retrieve *clang.FieldDecl
|
||||
// if .Array, use component.getArrayExprIndex() to get a c_uint which
|
||||
// can be passed to expr.getIndexExpr(expr_index) to get the *clang.Expr for the array index
|
||||
|
||||
return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO: implement complex OffsetOfExpr translation", .{});
|
||||
}
|
||||
|
||||
fn transBinaryOperator(
|
||||
c: *Context,
|
||||
scope: *Scope,
|
||||
|
||||
@@ -148,6 +148,8 @@ pub const Node = extern union {
|
||||
ptr_cast,
|
||||
/// @divExact(lhs, rhs)
|
||||
div_exact,
|
||||
/// @byteOffsetOf(lhs, rhs)
|
||||
byte_offset_of,
|
||||
|
||||
negate,
|
||||
negate_wrap,
|
||||
@@ -303,6 +305,7 @@ pub const Node = extern union {
|
||||
.std_mem_zeroinit,
|
||||
.ptr_cast,
|
||||
.div_exact,
|
||||
.byte_offset_of,
|
||||
=> Payload.BinOp,
|
||||
|
||||
.integer_literal,
|
||||
@@ -1135,6 +1138,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
|
||||
const payload = node.castTag(.div_exact).?.data;
|
||||
return renderBuiltinCall(c, "@divExact", &.{ payload.lhs, payload.rhs });
|
||||
},
|
||||
.byte_offset_of => {
|
||||
const payload = node.castTag(.byte_offset_of).?.data;
|
||||
return renderBuiltinCall(c, "@byteOffsetOf", &.{ payload.lhs, payload.rhs });
|
||||
},
|
||||
.sizeof => {
|
||||
const payload = node.castTag(.sizeof).?.data;
|
||||
return renderBuiltinCall(c, "@sizeOf", &.{payload});
|
||||
@@ -2001,6 +2008,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
|
||||
.array_type,
|
||||
.bool_to_int,
|
||||
.div_exact,
|
||||
.byte_offset_of,
|
||||
=> {
|
||||
// no grouping needed
|
||||
return renderNode(c, node);
|
||||
|
||||
@@ -2609,6 +2609,46 @@ const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct
|
||||
return reinterpret_cast<const struct ZigClangExpr *>(casted->getUnderlyingExpr());
|
||||
}
|
||||
|
||||
enum ZigClangOffsetOfNode_Kind ZigClangOffsetOfNode_getKind(const struct ZigClangOffsetOfNode *self) {
|
||||
auto casted = reinterpret_cast<const clang::OffsetOfNode *>(self);
|
||||
return (ZigClangOffsetOfNode_Kind)casted->getKind();
|
||||
}
|
||||
|
||||
unsigned ZigClangOffsetOfNode_getArrayExprIndex(const struct ZigClangOffsetOfNode *self) {
|
||||
auto casted = reinterpret_cast<const clang::OffsetOfNode *>(self);
|
||||
return casted->getArrayExprIndex();
|
||||
}
|
||||
|
||||
struct ZigClangFieldDecl *ZigClangOffsetOfNode_getField(const struct ZigClangOffsetOfNode *self) {
|
||||
auto casted = reinterpret_cast<const clang::OffsetOfNode *>(self);
|
||||
return reinterpret_cast<ZigClangFieldDecl *>(casted->getField());
|
||||
}
|
||||
|
||||
unsigned ZigClangOffsetOfExpr_getNumComponents(const struct ZigClangOffsetOfExpr *self) {
|
||||
auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
|
||||
return casted->getNumComponents();
|
||||
}
|
||||
|
||||
unsigned ZigClangOffsetOfExpr_getNumExpressions(const struct ZigClangOffsetOfExpr *self) {
|
||||
auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
|
||||
return casted->getNumExpressions();
|
||||
}
|
||||
|
||||
const struct ZigClangExpr *ZigClangOffsetOfExpr_getIndexExpr(const struct ZigClangOffsetOfExpr *self, unsigned idx) {
|
||||
auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
|
||||
return reinterpret_cast<const struct ZigClangExpr *>(casted->getIndexExpr(idx));
|
||||
}
|
||||
|
||||
const struct ZigClangOffsetOfNode *ZigClangOffsetOfExpr_getComponent(const struct ZigClangOffsetOfExpr *self, unsigned idx) {
|
||||
auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
|
||||
return reinterpret_cast<const struct ZigClangOffsetOfNode *>(&casted->getComponent(idx));
|
||||
}
|
||||
|
||||
ZigClangSourceLocation ZigClangOffsetOfExpr_getBeginLoc(const ZigClangOffsetOfExpr *self) {
|
||||
auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
|
||||
return bitcast(casted->getBeginLoc());
|
||||
}
|
||||
|
||||
struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *self) {
|
||||
auto casted = reinterpret_cast<const clang::ElaboratedType *>(self);
|
||||
return bitcast(casted->getNamedType());
|
||||
@@ -3008,6 +3048,11 @@ ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldD
|
||||
return bitcast(casted->getLocation());
|
||||
}
|
||||
|
||||
const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const struct ZigClangFieldDecl *self) {
|
||||
auto casted = reinterpret_cast<const clang::FieldDecl *>(self);
|
||||
return reinterpret_cast<const ZigClangRecordDecl *>(casted->getParent());
|
||||
}
|
||||
|
||||
ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *self) {
|
||||
auto casted = reinterpret_cast<const clang::FieldDecl *>(self);
|
||||
return bitcast(casted->getType());
|
||||
|
||||
@@ -928,6 +928,13 @@ enum ZigClangUnaryExprOrTypeTrait_Kind {
|
||||
ZigClangUnaryExprOrTypeTrait_KindPreferredAlignOf,
|
||||
};
|
||||
|
||||
enum ZigClangOffsetOfNode_Kind {
|
||||
ZigClangOffsetOfNode_KindArray,
|
||||
ZigClangOffsetOfNode_KindField,
|
||||
ZigClangOffsetOfNode_KindIdentifier,
|
||||
ZigClangOffsetOfNode_KindBase,
|
||||
};
|
||||
|
||||
ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const struct ZigClangSourceManager *,
|
||||
struct ZigClangSourceLocation Loc);
|
||||
ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const struct ZigClangSourceManager *,
|
||||
@@ -1161,6 +1168,16 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangTypeOfType_getUnderlyingType(const
|
||||
|
||||
ZIG_EXTERN_C const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct ZigClangTypeOfExprType *);
|
||||
|
||||
ZIG_EXTERN_C enum ZigClangOffsetOfNode_Kind ZigClangOffsetOfNode_getKind(const struct ZigClangOffsetOfNode *);
|
||||
ZIG_EXTERN_C unsigned ZigClangOffsetOfNode_getArrayExprIndex(const struct ZigClangOffsetOfNode *);
|
||||
ZIG_EXTERN_C struct ZigClangFieldDecl * ZigClangOffsetOfNode_getField(const struct ZigClangOffsetOfNode *);
|
||||
|
||||
ZIG_EXTERN_C unsigned ZigClangOffsetOfExpr_getNumComponents(const struct ZigClangOffsetOfExpr *);
|
||||
ZIG_EXTERN_C unsigned ZigClangOffsetOfExpr_getNumExpressions(const struct ZigClangOffsetOfExpr *);
|
||||
ZIG_EXTERN_C const struct ZigClangExpr *ZigClangOffsetOfExpr_getIndexExpr(const struct ZigClangOffsetOfExpr *, unsigned idx);
|
||||
ZIG_EXTERN_C const struct ZigClangOffsetOfNode *ZigClangOffsetOfExpr_getComponent(const struct ZigClangOffsetOfExpr *, unsigned idx);
|
||||
ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangOffsetOfExpr_getBeginLoc(const struct ZigClangOffsetOfExpr *);
|
||||
|
||||
ZIG_EXTERN_C struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *);
|
||||
ZIG_EXTERN_C enum ZigClangElaboratedTypeKeyword ZigClangElaboratedType_getKeyword(const struct ZigClangElaboratedType *);
|
||||
|
||||
@@ -1261,6 +1278,7 @@ ZIG_EXTERN_C bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *)
|
||||
ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *);
|
||||
ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *);
|
||||
ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *);
|
||||
ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const struct ZigClangFieldDecl *);
|
||||
|
||||
ZIG_EXTERN_C const struct ZigClangExpr *ZigClangEnumConstantDecl_getInitExpr(const struct ZigClangEnumConstantDecl *);
|
||||
ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct ZigClangEnumConstantDecl *);
|
||||
|
||||
@@ -1073,4 +1073,37 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
|
||||
cases.add("offsetof",
|
||||
\\#include <stddef.h>
|
||||
\\#include <stdlib.h>
|
||||
\\#define container_of(ptr, type, member) ({ \
|
||||
\\ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
\\ (type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
\\typedef struct {
|
||||
\\ int i;
|
||||
\\ struct { int x; char y; int z; } s;
|
||||
\\ float f;
|
||||
\\} container;
|
||||
\\int main(void) {
|
||||
\\ if (offsetof(container, i) != 0) abort();
|
||||
\\ if (offsetof(container, s) <= offsetof(container, i)) abort();
|
||||
\\ if (offsetof(container, f) <= offsetof(container, s)) abort();
|
||||
\\
|
||||
\\ container my_container;
|
||||
\\ typeof(my_container.s) *inner_member_pointer = &my_container.s;
|
||||
\\ float *float_member_pointer = &my_container.f;
|
||||
\\ int *anon_member_pointer = &my_container.s.z;
|
||||
\\ container *my_container_p;
|
||||
\\
|
||||
\\ my_container_p = container_of(inner_member_pointer, container, s);
|
||||
\\ if (my_container_p != &my_container) abort();
|
||||
\\
|
||||
\\ my_container_p = container_of(float_member_pointer, container, f);
|
||||
\\ if (my_container_p != &my_container) abort();
|
||||
\\
|
||||
\\ if (container_of(anon_member_pointer, typeof(my_container.s), z) != inner_member_pointer) abort();
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user