From bab871f3a10c124465db5c47f1815bacd99e728f Mon Sep 17 00:00:00 2001 From: Rico Tzschichholz Date: Thu, 3 Oct 2019 10:43:22 +0200 Subject: [PATCH] codegen: Allow passing/retrieving any delegate to/from varargs parameter Initialize target/notify cvalues of delegate-typed arguments/result of inferred varargs parameters and va_list.arg() calls. Only the actual function pointer will be passed or retrieved. The target and destroy values will be null. --- codegen/valaccodemethodcallmodule.vala | 24 +++++++++++++++++++++ tests/Makefile.am | 1 + tests/methods/varargs-delegate.vala | 30 ++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 tests/methods/varargs-delegate.vala diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala index d41e2904d..3c3290092 100644 --- a/codegen/valaccodemethodcallmodule.vala +++ b/codegen/valaccodemethodcallmodule.vala @@ -475,6 +475,17 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule { set_cvalue (arg, get_variable_cexpression (temp_var.name)); arg.target_value.value_type = arg.value_type; + if (arg.value_type is DelegateType && ((DelegateType) arg.value_type).delegate_symbol.has_target) { + // Initialize target/destroy cvalues to allow assignment of delegates from varargs + unowned GLibValue arg_value = (GLibValue) arg.target_value; + if (arg_value.delegate_target_cvalue == null) { + arg_value.delegate_target_cvalue = new CCodeConstant ("NULL"); + } + if (arg_value.delegate_target_destroy_notify_cvalue == null) { + arg_value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL"); + } + } + cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (arg)); } else { cexpr = handle_struct_argument (null, arg, cexpr); @@ -831,6 +842,19 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule { // TODO avoid code duplication result_type = expr.value_type; } + if (st != null && get_ccode_name (st) == "va_list" && ma.member_name == "arg") { + if (result_type is DelegateType && ((DelegateType) result_type).delegate_symbol.has_target) { + set_cvalue (expr, null); + // Initialize target/destroy cvalues to allow assignment of delegates from varargs + unowned GLibValue arg_value = (GLibValue) expr.target_value; + if (arg_value.delegate_target_cvalue == null) { + arg_value.delegate_target_cvalue = new CCodeConstant ("NULL"); + } + if (arg_value.delegate_target_destroy_notify_cvalue == null) { + arg_value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL"); + } + } + } } if (m != null && m.get_format_arg_index () >= 0) { diff --git a/tests/Makefile.am b/tests/Makefile.am index 068914630..f6b4c42a4 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -149,6 +149,7 @@ TESTS = \ methods/printf-invalid.test \ methods/printf-constructor.vala \ methods/printf-constructor-invalid.test \ + methods/varargs-delegate.vala \ methods/varargs-delegate-without-target.vala \ methods/varargs-gvalue.vala \ methods/varargs-out.vala \ diff --git a/tests/methods/varargs-delegate.vala b/tests/methods/varargs-delegate.vala new file mode 100644 index 000000000..a797d4c5d --- /dev/null +++ b/tests/methods/varargs-delegate.vala @@ -0,0 +1,30 @@ +delegate string Foo (); + +string foo (void* data) { + return "foo"; +} + +void bar (int first, ...) { + assert (first == 23); + var args = va_list (); + Foo** out_func = args.arg (); + *out_func = (Foo*) foo; +} + +void baz (int first, ...) { + assert (first == 42); + var args = va_list (); + Foo func = args.arg (); + assert (func () == "foo"); +} + +void main () { + { + Foo func; + bar (23, out func); + assert (func () == "foo"); + } + { + baz (42, foo); + } +} -- 2.47.2