[vala/staging: 2/2] vala: Require lvalue access of delegate target/destroy "fields"




commit cd25750b52d03962220663e5c29d2a336a5fceaa
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Sun Jan 16 19:25:51 2022 +0100

    vala: Require lvalue access of delegate target/destroy "fields"
    
    In addition to c054da918a40f8ef93c1a006034fb6ab4717c135
    
    See https://gitlab.gnome.org/GNOME/vala/issues/857

 codegen/valaccodememberaccessmodule.vala           |  4 +-
 tests/Makefile.am                                  |  1 +
 tests/delegates/member-target-destroy-2.c-expected | 91 ++++++++++++++++++++++
 tests/delegates/member-target-destroy-2.vala       | 20 +++++
 vala/valamemberaccess.vala                         |  8 ++
 5 files changed, 122 insertions(+), 2 deletions(-)
---
diff --git a/codegen/valaccodememberaccessmodule.vala b/codegen/valaccodememberaccessmodule.vala
index 0d5c8b4c3..40e6b790c 100644
--- a/codegen/valaccodememberaccessmodule.vala
+++ b/codegen/valaccodememberaccessmodule.vala
@@ -116,11 +116,11 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
                        set_cvalue (expr, get_array_length_cexpression (expr.inner, 1));
                } else if (expr.symbol_reference is DelegateTargetField) {
                        CCodeExpression delegate_target_destroy_notify;
-                       set_cvalue (expr, get_delegate_target_cexpression (expr.inner, out 
delegate_target_destroy_notify));
+                       set_cvalue (expr, get_delegate_target_cexpression (expr.inner, out 
delegate_target_destroy_notify) ?? new CCodeConstant ("NULL"));
                } else if (expr.symbol_reference is DelegateDestroyField) {
                        CCodeExpression delegate_target_destroy_notify;
                        get_delegate_target_cexpression (expr.inner, out delegate_target_destroy_notify);
-                       set_cvalue (expr, delegate_target_destroy_notify);
+                       set_cvalue (expr, delegate_target_destroy_notify ?? new CCodeConstant ("NULL"));
                } else if (expr.symbol_reference is GenericDupField) {
                        set_cvalue (expr, get_dup_func_expression (expr.inner.value_type, 
expr.source_reference));
                } else if (expr.symbol_reference is GenericDestroyField) {
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 1a5605dea..5156172d2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -441,6 +441,7 @@ TESTS = \
        delegates/lambda-outer-constant.test \
        delegates/lambda-shared-closure.vala \
        delegates/member-target-destroy.vala \
+       delegates/member-target-destroy-2.vala \
        delegates/params-array.vala \
        delegates/params-array-with-throws.vala \
        delegates/reference_transfer.vala \
diff --git a/tests/delegates/member-target-destroy-2.c-expected 
b/tests/delegates/member-target-destroy-2.c-expected
new file mode 100644
index 000000000..17b11e223
--- /dev/null
+++ b/tests/delegates/member-target-destroy-2.c-expected
@@ -0,0 +1,91 @@
+/* delegates_member_target_destroy_2.c generated by valac, the Vala compiler
+ * generated from delegates_member_target_destroy_2.vala, do not modify */
+
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined(VALA_EXTERN)
+#if defined(_MSC_VER)
+#define VALA_EXTERN __declspec(dllexport) extern
+#elif __GNUC__ >= 4
+#define VALA_EXTERN __attribute__((visibility("default"))) extern
+#else
+#define VALA_EXTERN extern
+#endif
+#endif
+
+typedef void (*FooFunc) (gpointer user_data);
+#define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, 
__LINE__, G_STRFUNC, msg);
+#define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, 
G_STRFUNC, msg); return; }
+#define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning 
(G_LOG_DOMAIN, G_STRFUNC, msg); return val; }
+#define _vala_warn_if_fail(expr, msg) if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, 
__LINE__, G_STRFUNC, msg);
+
+VALA_EXTERN void bar (const gchar* s);
+VALA_EXTERN void foo (FooFunc func,
+          gpointer func_target,
+          GDestroyNotify func_target_destroy_notify);
+static void _vala_main (void);
+
+void
+bar (const gchar* s)
+{
+       g_return_if_fail (s != NULL);
+       _vala_assert (g_strcmp0 (s, "foo") == 0, "s == \"foo\"");
+}
+
+void
+foo (FooFunc func,
+     gpointer func_target,
+     GDestroyNotify func_target_destroy_notify)
+{
+       GDestroyNotify _tmp0_;
+       _vala_assert (g_strcmp0 (func_target, "foo") == 0, "func.target == \"foo\"");
+       _tmp0_ = g_free;
+       _vala_assert (func_target_destroy_notify == _tmp0_, "func.destroy == g_free");
+       func (func_target);
+       (func_target_destroy_notify == NULL) ? NULL : (func_target_destroy_notify (func_target), NULL);
+       func = NULL;
+       func_target = NULL;
+       func_target_destroy_notify = NULL;
+}
+
+static void
+_vala_main (void)
+{
+       FooFunc func = NULL;
+       gpointer func_target;
+       GDestroyNotify func_target_destroy_notify;
+       gchar* _tmp0_;
+       GDestroyNotify _tmp1_;
+       FooFunc _tmp2_;
+       gpointer _tmp2__target;
+       GDestroyNotify _tmp2__target_destroy_notify;
+       func = (FooFunc) bar;
+       func_target = NULL;
+       func_target_destroy_notify = NULL;
+       _tmp0_ = g_strdup ("foo");
+       func_target = _tmp0_;
+       _tmp1_ = g_free;
+       func_target_destroy_notify = _tmp1_;
+       _tmp2_ = func;
+       _tmp2__target = func_target;
+       _tmp2__target_destroy_notify = func_target_destroy_notify;
+       func = NULL;
+       func_target = NULL;
+       func_target_destroy_notify = NULL;
+       foo (_tmp2_, _tmp2__target, _tmp2__target_destroy_notify);
+       (func_target_destroy_notify == NULL) ? NULL : (func_target_destroy_notify (func_target), NULL);
+       func = NULL;
+       func_target = NULL;
+       func_target_destroy_notify = NULL;
+}
+
+int
+main (int argc,
+      char ** argv)
+{
+       _vala_main ();
+       return 0;
+}
+
diff --git a/tests/delegates/member-target-destroy-2.vala b/tests/delegates/member-target-destroy-2.vala
new file mode 100644
index 000000000..62ecd263a
--- /dev/null
+++ b/tests/delegates/member-target-destroy-2.vala
@@ -0,0 +1,20 @@
+delegate void FooFunc ();
+
+void bar (string s) {
+       assert (s == "foo");
+}
+
+void foo (owned FooFunc func) {
+       assert (func.target == "foo");
+       assert (func.destroy == g_free);
+       func ();
+}
+
+void main () {
+       FooFunc func = (FooFunc) bar;
+
+       func.target = "foo".dup ();
+       func.destroy = g_free;
+
+       foo ((owned) func);
+}
diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala
index 39a7af72c..0f5cac118 100644
--- a/vala/valamemberaccess.vala
+++ b/vala/valamemberaccess.vala
@@ -1129,6 +1129,14 @@ public class Vala.MemberAccess : Expression {
                        }
                }
 
+               if (symbol_reference is DelegateTargetField || symbol_reference is DelegateDestroyField) {
+                       inner.lvalue = true;
+                       if (ma != null) {
+                               ma.lvalue = true;
+                               ma.check_lvalue_access ();
+                       }
+               }
+
                if (symbol_reference is Method && ((Method) symbol_reference).get_attribute 
("DestroysInstance") != null) {
                        unowned Class? cl = ((Method) symbol_reference).parent_symbol as Class;
                        if (cl != null && cl.is_compact && ma != null) {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]