diff --git a/src/clang.zig b/src/clang.zig index 60afa28cf1..0d18ae42b3 100644 --- a/src/clang.zig +++ b/src/clang.zig @@ -537,6 +537,11 @@ pub const FunctionType = opaque { extern fn ZigClangFunctionType_getReturnType(*const FunctionType) QualType; }; +pub const GenericSelectionExpr = opaque { + pub const getResultExpr = ZigClangGenericSelectionExpr_getResultExpr; + extern fn ZigClangGenericSelectionExpr_getResultExpr(*const GenericSelectionExpr) *const Expr; +}; + pub const IfStmt = opaque { pub const getThen = ZigClangIfStmt_getThen; extern fn ZigClangIfStmt_getThen(*const IfStmt) *const Stmt; diff --git a/src/translate_c.zig b/src/translate_c.zig index bd6c306960..d2c5cd6233 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -1058,6 +1058,10 @@ fn transStmt( const compound_literal = @ptrCast(*const clang.CompoundLiteralExpr, stmt); return transExpr(c, scope, compound_literal.getInitializer(), result_used); }, + .GenericSelectionExprClass => { + const gen_sel = @ptrCast(*const clang.GenericSelectionExpr, stmt); + return transExpr(c, scope, gen_sel.getResultExpr(), result_used); + }, else => { return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)}); }, @@ -1582,6 +1586,10 @@ fn exprIsNarrowStringLiteral(expr: *const clang.Expr) bool { const op_expr = @ptrCast(*const clang.ParenExpr, expr).getSubExpr(); return exprIsNarrowStringLiteral(op_expr); }, + .GenericSelectionExprClass => { + const gen_sel = @ptrCast(*const clang.GenericSelectionExpr, expr); + return exprIsNarrowStringLiteral(gen_sel.getResultExpr()); + }, else => return false, } } @@ -2726,6 +2734,10 @@ fn cIsFunctionDeclRef(expr: *const clang.Expr) bool { const opcode = un_op.getOpcode(); return (opcode == .AddrOf or opcode == .Deref) and cIsFunctionDeclRef(un_op.getSubExpr()); }, + .GenericSelectionExprClass => { + const gen_sel = @ptrCast(*const clang.GenericSelectionExpr, expr); + return cIsFunctionDeclRef(gen_sel.getResultExpr()); + }, else => return false, } } diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index b789df0764..95e9e390a1 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -2445,6 +2445,11 @@ struct ZigClangQualType ZigClangFunctionType_getReturnType(const struct ZigClang return bitcast(casted->getReturnType()); } +const struct ZigClangExpr *ZigClangGenericSelectionExpr_getResultExpr(const struct ZigClangGenericSelectionExpr *self) { + auto casted = reinterpret_cast(self); + return reinterpret_cast(casted->getResultExpr()); +} + bool ZigClangFunctionProtoType_isVariadic(const struct ZigClangFunctionProtoType *self) { auto casted = reinterpret_cast(self); return casted->isVariadic(); diff --git a/src/zig_clang.h b/src/zig_clang.h index 34e2d5afb7..59eacf7587 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -1116,6 +1116,8 @@ ZIG_EXTERN_C bool ZigClangFunctionType_getNoReturnAttr(const struct ZigClangFunc ZIG_EXTERN_C enum ZigClangCallingConv ZigClangFunctionType_getCallConv(const struct ZigClangFunctionType *self); ZIG_EXTERN_C struct ZigClangQualType ZigClangFunctionType_getReturnType(const struct ZigClangFunctionType *self); +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangGenericSelectionExpr_getResultExpr(const struct ZigClangGenericSelectionExpr *self); + ZIG_EXTERN_C bool ZigClangFunctionProtoType_isVariadic(const struct ZigClangFunctionProtoType *self); ZIG_EXTERN_C unsigned ZigClangFunctionProtoType_getNumParams(const struct ZigClangFunctionProtoType *self); ZIG_EXTERN_C struct ZigClangQualType ZigClangFunctionProtoType_getParamType(const struct ZigClangFunctionProtoType *self, unsigned i); diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig index 01df88c852..bda401d08c 100644 --- a/test/run_translated_c.zig +++ b/test/run_translated_c.zig @@ -1187,4 +1187,38 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { \\ return 0; \\} , ""); + + cases.add("Generic selections", + \\#include + \\#include + \\#include + \\#define my_generic_fn(X) _Generic((X), \ + \\ int: abs, \ + \\ char *: strlen, \ + \\ size_t: malloc, \ + \\ default: free \ + \\)(X) + \\#define my_generic_val(X) _Generic((X), \ + \\ int: 1, \ + \\ const char *: "bar" \ + \\) + \\int main(void) { + \\ if (my_generic_val(100) != 1) abort(); + \\ + \\ const char *foo = "foo"; + \\ const char *bar = my_generic_val(foo); + \\ if (strcmp(bar, "bar") != 0) abort(); + \\ + \\ if (my_generic_fn(-42) != 42) abort(); + \\ if (my_generic_fn("hello") != 5) abort(); + \\ + \\ size_t size = 8192; + \\ uint8_t *mem = my_generic_fn(size); + \\ memset(mem, 42, size); + \\ if (mem[size - 1] != 42) abort(); + \\ my_generic_fn(mem); + \\ + \\ return 0; + \\} + , ""); }