| 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,7 +848,10 @@ pub const UnaryOperator = opaque { |
| 848 | extern fn ZigClangUnaryOperator_getBeginLoc(*const UnaryOperator) SourceLocation; | 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 | pub const VarDecl = opaque { | 856 | pub const VarDecl = opaque { |
| 854 | pub const getLocation = ZigClangVarDecl_getLocation; | 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,6 +3208,38 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const clang.ArraySub |
| 3208 | return maybeSuppressResult(rp, scope, result_used, &node.base); | 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 | fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.CallExpr, result_used: ResultUsed) TransError!*ast.Node { | 3243 | fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.CallExpr, result_used: ResultUsed) TransError!*ast.Node { |
| 3212 | const callee = stmt.getCallee(); | 3244 | const callee = stmt.getCallee(); |
| 3213 | var raw_fn_expr = try transExpr(rp, scope, callee, .used, .r_value); | 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,24 +3247,9 @@ fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.CallExpr, r |
| 3215 | var is_ptr = false; | 3247 | var is_ptr = false; |
| 3216 | const fn_ty = qualTypeGetFnProto(callee.getType(), &is_ptr); | 3248 | const fn_ty = qualTypeGetFnProto(callee.getType(), &is_ptr); |
| 3217 | 3249 | ||
| 3218 | const fn_expr = if (is_ptr and fn_ty != null) blk: { | 3250 | const fn_expr = if (is_ptr and fn_ty != null and !cIsFunctionDeclRef(callee)) |
| 3219 | if (callee.getStmtClass() == .ImplicitCastExprClass) { | 3251 | try transCreateNodeUnwrapNull(rp.c, raw_fn_expr) |
| 3220 | const implicit_cast = @ptrCast(*const clang.ImplicitCastExpr, callee); | 3252 | else |
| 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 | ||
| 3236 | raw_fn_expr; | 3253 | raw_fn_expr; |
| 3237 | 3254 | ||
| 3238 | const num_args = stmt.getNumArgs(); | 3255 | const num_args = stmt.getNumArgs(); |
| ... | @@ -3379,6 +3396,9 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.UnaryO | ... | @@ -3379,6 +3396,9 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.UnaryO |
| 3379 | else | 3396 | else |
| 3380 | return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used), | 3397 | return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used), |
| 3381 | .AddrOf => { | 3398 | .AddrOf => { |
| 3399 | if (cIsFunctionDeclRef(op_expr)) { | ||
| 3400 | return transExpr(rp, scope, op_expr, used, .r_value); | ||
| 3401 | } | ||
| 3382 | const op_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); | 3402 | const op_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); |
| 3383 | op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value); | 3403 | op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value); |
| 3384 | return &op_node.base; | 3404 | return &op_node.base; |
src/zig_clang.cpp+5| ... | @@ -2773,6 +2773,11 @@ struct ZigClangSourceLocation ZigClangUnaryOperator_getBeginLoc(const struct Zig | ... | @@ -2773,6 +2773,11 @@ struct ZigClangSourceLocation ZigClangUnaryOperator_getBeginLoc(const struct Zig |
| 2773 | return bitcast(casted->getBeginLoc()); | 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 | const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *self) { | 2781 | const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *self) { |
| 2777 | auto casted = reinterpret_cast<const clang::WhileStmt *>(self); | 2782 | auto casted = reinterpret_cast<const clang::WhileStmt *>(self); |
| 2778 | return reinterpret_cast<const struct ZigClangExpr *>(casted->getCond()); | 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,6 +1200,8 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangUnaryOperator_getType(const struct |
| 1200 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangUnaryOperator_getSubExpr(const struct ZigClangUnaryOperator *); | 1200 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangUnaryOperator_getSubExpr(const struct ZigClangUnaryOperator *); |
| 1201 | ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangUnaryOperator_getBeginLoc(const struct ZigClangUnaryOperator *); | 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 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *); | 1205 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *); |
| 1204 | ZIG_EXTERN_C const struct ZigClangStmt *ZigClangWhileStmt_getBody(const struct ZigClangWhileStmt *); | 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,4 +818,60 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 818 | \\ return 0; | 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,8 +2802,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2802 | \\ fn_f64(3); | 2802 | \\ fn_f64(3); |
| 2803 | \\ fn_bool(@as(c_int, 123) != 0); | 2803 | \\ fn_bool(@as(c_int, 123) != 0); |
| 2804 | \\ fn_bool(@as(c_int, 0) != 0); | 2804 | \\ fn_bool(@as(c_int, 0) != 0); |
| 2805 | \\ fn_bool(@ptrToInt(&fn_int) != 0); | 2805 | \\ fn_bool(@ptrToInt(fn_int) != 0); |
| 2806 | \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int))); | 2806 | \\ fn_int(@intCast(c_int, @ptrToInt(fn_int))); |
| 2807 | \\ fn_ptr(@intToPtr(?*c_void, @as(c_int, 42))); | 2807 | \\ fn_ptr(@intToPtr(?*c_void, @as(c_int, 42))); |
| 2808 | \\} | 2808 | \\} |
| 2809 | }); | 2809 | }); |