From: Rico Tzschichholz Date: Mon, 25 Mar 2024 14:34:52 +0000 (+0100) Subject: codegen: Update array length variable passed to null-terminated ref parameter X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=43a348b1eebd57a427275ca58a84cd32d30ebb0d;p=thirdparty%2Fvala.git codegen: Update array length variable passed to null-terminated ref parameter Fixes https://gitlab.gnome.org/GNOME/vala/issues/1536 --- diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala index 1368d3c3d..dcb8f8bab 100644 --- a/codegen/valaccodemethodcallmodule.vala +++ b/codegen/valaccodemethodcallmodule.vala @@ -980,9 +980,22 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule { var unary = arg as UnaryExpression; + // handle ref null terminated arrays + if (unary != null && unary.operator == UnaryOperator.REF + && unary.inner.symbol_reference != null && get_ccode_array_length (unary.inner.symbol_reference)) { + if (param != null && get_ccode_array_null_terminated (param) + && param.variable_type is ArrayType && ((ArrayType) param.variable_type).rank == 1) { + requires_array_length = true; + var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length")); + len_call.add_argument (get_cvalue_ (unary.inner.target_value)); + ccode.add_assignment (get_array_length_cvalue (unary.inner.target_value, 1), len_call); + } + } + // update possible stale _*_size_ variable - if (unary != null && unary.operator == UnaryOperator.REF) { - if (param != null && get_ccode_array_length (param) && param.variable_type is ArrayType + if (unary != null && unary.operator == UnaryOperator.REF + && unary.inner.symbol_reference != null && get_ccode_array_length (unary.inner.symbol_reference)) { + if (param != null && param.variable_type is ArrayType && !((ArrayType) param.variable_type).fixed_length && ((ArrayType) param.variable_type).rank == 1) { unowned Variable? array_var = unary.inner.symbol_reference as Variable; if ((array_var is LocalVariable || array_var is Field) && array_var.is_internal_symbol () diff --git a/tests/Makefile.am b/tests/Makefile.am index 600e69977..42d81a83d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -214,6 +214,7 @@ TESTS = \ methods/parameter-out-free-on-error.vala \ methods/parameter-ref-array-resize.vala \ methods/parameter-ref-array-resize-captured.vala \ + methods/parameter-ref-array-resize-null-terminated.vala \ methods/parameter-ref-delegate.vala \ methods/parameter-ref-element-access.vala \ methods/preconditions-temp-variables.vala \ diff --git a/tests/methods/parameter-ref-array-resize-null-terminated.c-expected b/tests/methods/parameter-ref-array-resize-null-terminated.c-expected new file mode 100644 index 000000000..331362993 --- /dev/null +++ b/tests/methods/parameter-ref-array-resize-null-terminated.c-expected @@ -0,0 +1,190 @@ +/* methods_parameter_ref_array_resize_null_terminated.c generated by valac, the Vala compiler + * generated from methods_parameter_ref_array_resize_null_terminated.vala, do not modify */ + +#include +#include +#include + +#if !defined(VALA_STRICT_C) +#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ >= 14) +#pragma GCC diagnostic warning "-Wincompatible-pointer-types" +#elif defined(__clang__) && (__clang_major__ >= 16) +#pragma clang diagnostic ignored "-Wincompatible-function-pointer-types" +#pragma clang diagnostic ignored "-Wincompatible-pointer-types" +#endif +#endif +#if !defined(VALA_EXTERN) +#if defined(_WIN32) || defined(__CYGWIN__) +#define VALA_EXTERN __declspec(dllexport) extern +#elif __GNUC__ >= 4 +#define VALA_EXTERN __attribute__((visibility("default"))) extern +#else +#define VALA_EXTERN extern +#endif +#endif + +#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 foo (gchar*** bar); +VALA_EXTERN void faz (gchar*** bar); +static void _vala_main (void); +static void _vala_array_destroy (gpointer array, + gssize array_length, + GDestroyNotify destroy_func); +static void _vala_array_free (gpointer array, + gssize array_length, + GDestroyNotify destroy_func); +static gssize _vala_array_length (gpointer array); + +void +foo (gchar*** bar) +{ + gchar* _tmp0_; + gchar* _tmp1_; + gchar* _tmp2_; + gchar* _tmp3_; + gchar** _tmp4_; + _tmp0_ = g_strdup ("foo"); + _tmp1_ = g_strdup ("bar"); + _tmp2_ = g_strdup ("manam"); + _tmp3_ = g_strdup ("!"); + _tmp4_ = g_new0 (gchar*, 4 + 1); + _tmp4_[0] = _tmp0_; + _tmp4_[1] = _tmp1_; + _tmp4_[2] = _tmp2_; + _tmp4_[3] = _tmp3_; + *bar = (_vala_array_free (*bar, _vala_array_length (*bar), (GDestroyNotify) g_free), NULL); + *bar = _tmp4_; +} + +void +faz (gchar*** bar) +{ + foo (bar); +} + +static void +_vala_main (void) +{ + { + gchar** bar = NULL; + gchar* _tmp0_; + gchar** _tmp1_; + gint bar_length1; + gint _bar_size_; + gchar** _tmp2_; + gint _tmp2__length1; + gchar** _tmp3_; + gint _tmp3__length1; + const gchar* _tmp4_; + gchar** _tmp5_; + gint _tmp5__length1; + const gchar* _tmp6_; + _tmp0_ = g_strdup ("bar"); + _tmp1_ = g_new0 (gchar*, 1 + 1); + _tmp1_[0] = _tmp0_; + bar = _tmp1_; + bar_length1 = 1; + _bar_size_ = bar_length1; + foo (&bar); + bar_length1 = _vala_array_length (bar); + _bar_size_ = bar_length1; + _tmp2_ = bar; + _tmp2__length1 = bar_length1; + _vala_assert (_tmp2__length1 == 4, "bar.length == 4"); + _tmp3_ = bar; + _tmp3__length1 = bar_length1; + _tmp4_ = _tmp3_[2]; + _vala_assert (g_strcmp0 (_tmp4_, "manam") == 0, "bar[2] == \"manam\""); + _tmp5_ = bar; + _tmp5__length1 = bar_length1; + _tmp6_ = _tmp5_[4]; + _vala_assert (_tmp6_ == NULL, "bar[4] == null"); + bar = (_vala_array_free (bar, bar_length1, (GDestroyNotify) g_free), NULL); + } + { + gchar** bar = NULL; + gchar* _tmp7_; + gchar** _tmp8_; + gint bar_length1; + gint _bar_size_; + gchar** _tmp9_; + gint _tmp9__length1; + gchar** _tmp10_; + gint _tmp10__length1; + const gchar* _tmp11_; + gchar** _tmp12_; + gint _tmp12__length1; + const gchar* _tmp13_; + _tmp7_ = g_strdup ("bar"); + _tmp8_ = g_new0 (gchar*, 1 + 1); + _tmp8_[0] = _tmp7_; + bar = _tmp8_; + bar_length1 = 1; + _bar_size_ = bar_length1; + faz (&bar); + bar_length1 = _vala_array_length (bar); + _bar_size_ = bar_length1; + _tmp9_ = bar; + _tmp9__length1 = bar_length1; + _vala_assert (_tmp9__length1 == 4, "bar.length == 4"); + _tmp10_ = bar; + _tmp10__length1 = bar_length1; + _tmp11_ = _tmp10_[2]; + _vala_assert (g_strcmp0 (_tmp11_, "manam") == 0, "bar[2] == \"manam\""); + _tmp12_ = bar; + _tmp12__length1 = bar_length1; + _tmp13_ = _tmp12_[4]; + _vala_assert (_tmp13_ == NULL, "bar[4] == null"); + bar = (_vala_array_free (bar, bar_length1, (GDestroyNotify) g_free), NULL); + } +} + +int +main (int argc, + char ** argv) +{ + _vala_main (); + return 0; +} + +static void +_vala_array_destroy (gpointer array, + gssize array_length, + GDestroyNotify destroy_func) +{ + if ((array != NULL) && (destroy_func != NULL)) { + gssize i; + for (i = 0; i < array_length; i = i + 1) { + if (((gpointer*) array)[i] != NULL) { + destroy_func (((gpointer*) array)[i]); + } + } + } +} + +static void +_vala_array_free (gpointer array, + gssize array_length, + GDestroyNotify destroy_func) +{ + _vala_array_destroy (array, array_length, destroy_func); + g_free (array); +} + +static gssize +_vala_array_length (gpointer array) +{ + gssize length; + length = 0; + if (array) { + while (((gpointer*) array)[length]) { + length++; + } + } + return length; +} + diff --git a/tests/methods/parameter-ref-array-resize-null-terminated.vala b/tests/methods/parameter-ref-array-resize-null-terminated.vala new file mode 100644 index 000000000..af6ec401e --- /dev/null +++ b/tests/methods/parameter-ref-array-resize-null-terminated.vala @@ -0,0 +1,24 @@ +void foo ([CCode (array_length = false, array_null_terminated = true)] ref string[] bar) { + bar = { "foo", "bar", "manam", "!" }; +} + +void faz ([CCode (array_length = false, array_null_terminated = true)] ref string[] bar) { + foo (ref bar); +} + +void main () { + { + string[] bar = { "bar" }; + foo (ref bar); + assert (bar.length == 4); + assert (bar[2] == "manam"); + assert (bar[4] == null); + } + { + string[] bar = { "bar" }; + faz (ref bar); + assert (bar.length == 4); + assert (bar[2] == "manam"); + assert (bar[4] == null); + } +}