| author | |
| committer | |
| log | 221f1d898c39e9ea25f1d7fc9642bfbb3c97e894 |
| tree | e7fd7ba2007c9af7cf55c9114b677b62b0186a71 |
| parent | 1adac0a55bafbba864228ac38c4684612e84f522 |
Omit address-of operator if operand is a function.
Improve handling of function-call translation when using function pointers
Fixes #41246 files changed, 107 insertions(+), 21 deletions(-)
src/clang.zig+4-1| ... | ... | @@ -848,7 +848,10 @@ pub const UnaryOperator = opaque { |
| 848 | 848 | extern fn ZigClangUnaryOperator_getBeginLoc(*const UnaryOperator) SourceLocation; |
| 849 | 849 | }; |
| 850 | 850 | |
| 851 | pub const ValueDecl = opaque {}; | |
| 851 | pub const ValueDecl = opaque { | |
| 852 | pub const getType = ZigClangValueDecl_getType; | |
| 853 | extern fn ZigClangValueDecl_getType(*const ValueDecl) QualType; | |
| 854 | }; | |
| 852 | 855 | |
| 853 | 856 | pub const VarDecl = opaque { |
| 854 | 857 | pub const getLocation = ZigClangVarDecl_getLocation; |
src/translate_c.zig+38-18| ... | ... | @@ -3208,6 +3208,38 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const clang.ArraySub |
| 3208 | 3208 | return maybeSuppressResult(rp, scope, result_used, &node.base); |
| 3209 | 3209 | } |
| 3210 | 3210 | |
| 3211 | /// Check if an expression is ultimately a reference to a function declaration | |
| 3212 | /// (which means it should not be unwrapped with `.?` in translated code) | |
| 3213 | fn cIsFunctionDeclRef(expr: *const clang.Expr) bool { | |
| 3214 | switch (expr.getStmtClass()) { | |
| 3215 | .ParenExprClass => { | |
| 3216 | const op_expr = @ptrCast(*const clang.ParenExpr, expr).getSubExpr(); | |
| 3217 | return cIsFunctionDeclRef(op_expr); | |
| 3218 | }, | |
| 3219 | .DeclRefExprClass => { | |
| 3220 | const decl_ref = @ptrCast(*const clang.DeclRefExpr, expr); | |
| 3221 | const value_decl = decl_ref.getDecl(); | |
| 3222 | const qt = value_decl.getType(); | |
| 3223 | return qualTypeChildIsFnProto(qt); | |
| 3224 | }, | |
| 3225 | .ImplicitCastExprClass => { | |
| 3226 | const implicit_cast = @ptrCast(*const clang.ImplicitCastExpr, expr); | |
| 3227 | const cast_kind = implicit_cast.getCastKind(); | |
| 3228 | if (cast_kind == .BuiltinFnToFnPtr) return true; | |
| 3229 | if (cast_kind == .FunctionToPointerDecay) { | |
| 3230 | return cIsFunctionDeclRef(implicit_cast.getSubExpr()); | |
| 3231 | } | |
| 3232 | return false; | |
| 3233 | }, | |
| 3234 | .UnaryOperatorClass => { | |
| 3235 | const un_op = @ptrCast(*const clang.UnaryOperator, expr); | |
| 3236 | const opcode = un_op.getOpcode(); | |
| 3237 | return (opcode == .AddrOf or opcode == .Deref) and cIsFunctionDeclRef(un_op.getSubExpr()); | |
| 3238 | }, | |
| 3239 | else => return false, | |
| 3240 | } | |
| 3241 | } | |
| 3242 | ||
| 3211 | 3243 | fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.CallExpr, result_used: ResultUsed) TransError!*ast.Node { |
| 3212 | 3244 | const callee = stmt.getCallee(); |
| 3213 | 3245 | var raw_fn_expr = try transExpr(rp, scope, callee, .used, .r_value); |
| ... | ... | @@ -3215,24 +3247,9 @@ fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.CallExpr, r |
| 3215 | 3247 | var is_ptr = false; |
| 3216 | 3248 | const fn_ty = qualTypeGetFnProto(callee.getType(), &is_ptr); |
| 3217 | 3249 | |
| 3218 | const fn_expr = if (is_ptr and fn_ty != null) blk: { | |
| 3219 | if (callee.getStmtClass() == .ImplicitCastExprClass) { | |
| 3220 | const implicit_cast = @ptrCast(*const clang.ImplicitCastExpr, callee); | |
| 3221 | const cast_kind = implicit_cast.getCastKind(); | |
| 3222 | if (cast_kind == .BuiltinFnToFnPtr) break :blk raw_fn_expr; | |
| 3223 | if (cast_kind == .FunctionToPointerDecay) { | |
| 3224 | const subexpr = implicit_cast.getSubExpr(); | |
| 3225 | if (subexpr.getStmtClass() == .DeclRefExprClass) { | |
| 3226 | const decl_ref = @ptrCast(*const clang.DeclRefExpr, subexpr); | |
| 3227 | const named_decl = decl_ref.getFoundDecl(); | |
| 3228 | if (@ptrCast(*const clang.Decl, named_decl).getKind() == .Function) { | |
| 3229 | break :blk raw_fn_expr; | |
| 3230 | } | |
| 3231 | } | |
| 3232 | } | |
| 3233 | } | |
| 3234 | break :blk try transCreateNodeUnwrapNull(rp.c, raw_fn_expr); | |
| 3235 | } else | |
| 3250 | const fn_expr = if (is_ptr and fn_ty != null and !cIsFunctionDeclRef(callee)) | |
| 3251 | try transCreateNodeUnwrapNull(rp.c, raw_fn_expr) | |
| 3252 | else | |
| 3236 | 3253 | raw_fn_expr; |
| 3237 | 3254 | |
| 3238 | 3255 | const num_args = stmt.getNumArgs(); |
| ... | ... | @@ -3379,6 +3396,9 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.UnaryO |
| 3379 | 3396 | else |
| 3380 | 3397 | return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used), |
| 3381 | 3398 | .AddrOf => { |
| 3399 | if (cIsFunctionDeclRef(op_expr)) { | |
| 3400 | return transExpr(rp, scope, op_expr, used, .r_value); | |
| 3401 | } | |
| 3382 | 3402 | const op_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); |
| 3383 | 3403 | op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value); |
| 3384 | 3404 | return &op_node.base; |
src/zig_clang.cpp+5| ... | ... | @@ -2773,6 +2773,11 @@ struct ZigClangSourceLocation ZigClangUnaryOperator_getBeginLoc(const struct Zig |
| 2773 | 2773 | return bitcast(casted->getBeginLoc()); |
| 2774 | 2774 | } |
| 2775 | 2775 | |
| 2776 | struct ZigClangQualType ZigClangValueDecl_getType(const struct ZigClangValueDecl *self) { | |
| 2777 | auto casted = reinterpret_cast<const clang::ValueDecl *>(self); | |
| 2778 | return bitcast(casted->getType()); | |
| 2779 | } | |
| 2780 | ||
| 2776 | 2781 | const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *self) { |
| 2777 | 2782 | auto casted = reinterpret_cast<const clang::WhileStmt *>(self); |
| 2778 | 2783 | return reinterpret_cast<const struct ZigClangExpr *>(casted->getCond()); |
src/zig_clang.h+2| ... | ... | @@ -1200,6 +1200,8 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangUnaryOperator_getType(const struct |
| 1200 | 1200 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangUnaryOperator_getSubExpr(const struct ZigClangUnaryOperator *); |
| 1201 | 1201 | ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangUnaryOperator_getBeginLoc(const struct ZigClangUnaryOperator *); |
| 1202 | 1202 | |
| 1203 | ZIG_EXTERN_C struct ZigClangQualType ZigClangValueDecl_getType(const struct ZigClangValueDecl *); | |
| 1204 | ||
| 1203 | 1205 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *); |
| 1204 | 1206 | ZIG_EXTERN_C const struct ZigClangStmt *ZigClangWhileStmt_getBody(const struct ZigClangWhileStmt *); |
| 1205 | 1207 |
test/run_translated_c.zig+56| ... | ... | @@ -818,4 +818,60 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 818 | 818 | \\ return 0; |
| 819 | 819 | \\} |
| 820 | 820 | , ""); |
| 821 | ||
| 822 | cases.add("Address of function is no-op", | |
| 823 | \\#include <stdlib.h> | |
| 824 | \\#include <stdbool.h> | |
| 825 | \\typedef int (*myfunc)(int); | |
| 826 | \\int a(int arg) { return arg + 1;} | |
| 827 | \\int b(int arg) { return arg + 2;} | |
| 828 | \\int caller(myfunc fn, int arg) { | |
| 829 | \\ return fn(arg); | |
| 830 | \\} | |
| 831 | \\int main() { | |
| 832 | \\ myfunc arr[3] = {&a, &b, a}; | |
| 833 | \\ myfunc foo = a; | |
| 834 | \\ myfunc bar = &(a); | |
| 835 | \\ if (foo != bar) abort(); | |
| 836 | \\ if (arr[0] == arr[1]) abort(); | |
| 837 | \\ if (arr[0] != arr[2]) abort(); | |
| 838 | \\ if (caller(b, 40) != 42) abort(); | |
| 839 | \\ if (caller(&b, 40) != 42) abort(); | |
| 840 | \\ return 0; | |
| 841 | \\} | |
| 842 | , ""); | |
| 843 | ||
| 844 | cases.add("Obscure ways of calling functions; issue #4124", | |
| 845 | \\#include <stdlib.h> | |
| 846 | \\static int add(int a, int b) { | |
| 847 | \\ return a + b; | |
| 848 | \\} | |
| 849 | \\typedef int (*adder)(int, int); | |
| 850 | \\typedef void (*funcptr)(void); | |
| 851 | \\int main() { | |
| 852 | \\ if ((add)(1, 2) != 3) abort(); | |
| 853 | \\ if ((&add)(1, 2) != 3) abort(); | |
| 854 | \\ if (add(3, 1) != 4) abort(); | |
| 855 | \\ if ((*add)(2, 3) != 5) abort(); | |
| 856 | \\ if ((**add)(7, -1) != 6) abort(); | |
| 857 | \\ if ((***add)(-2, 9) != 7) abort(); | |
| 858 | \\ | |
| 859 | \\ int (*ptr)(int a, int b); | |
| 860 | \\ ptr = add; | |
| 861 | \\ | |
| 862 | \\ if (ptr(1, 2) != 3) abort(); | |
| 863 | \\ if ((*ptr)(3, 1) != 4) abort(); | |
| 864 | \\ if ((**ptr)(2, 3) != 5) abort(); | |
| 865 | \\ if ((***ptr)(7, -1) != 6) abort(); | |
| 866 | \\ if ((****ptr)(-2, 9) != 7) abort(); | |
| 867 | \\ | |
| 868 | \\ funcptr addr1 = (funcptr)(add); | |
| 869 | \\ funcptr addr2 = (funcptr)(&add); | |
| 870 | \\ | |
| 871 | \\ if (addr1 != addr2) abort(); | |
| 872 | \\ if (((int(*)(int, int))addr1)(1, 2) != 3) abort(); | |
| 873 | \\ if (((adder)addr2)(1, 2) != 3) abort(); | |
| 874 | \\ return 0; | |
| 875 | \\} | |
| 876 | , ""); | |
| 821 | 877 | } |
test/translate_c.zig+2-2| ... | ... | @@ -2802,8 +2802,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2802 | 2802 | \\ fn_f64(3); |
| 2803 | 2803 | \\ fn_bool(@as(c_int, 123) != 0); |
| 2804 | 2804 | \\ fn_bool(@as(c_int, 0) != 0); |
| 2805 | \\ fn_bool(@ptrToInt(&fn_int) != 0); | |
| 2806 | \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int))); | |
| 2805 | \\ fn_bool(@ptrToInt(fn_int) != 0); | |
| 2806 | \\ fn_int(@intCast(c_int, @ptrToInt(fn_int))); | |
| 2807 | 2807 | \\ fn_ptr(@intToPtr(?*c_void, @as(c_int, 42))); |
| 2808 | 2808 | \\} |
| 2809 | 2809 | }); |