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:
Evan Haas
2021-02-25 16:43:39 -08:00
committed by Veikka Tuominen
parent 0423f0f7d8
commit 294ee1bbc9
6 changed files with 194 additions and 0 deletions

View File

@@ -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,

View File

@@ -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,

View File

@@ -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);

View File

@@ -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());

View File

@@ -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 *);

View File

@@ -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;
\\}
, "");
}