Repository: pyccel/pyccel (python)

Issue:
Variables are used uninitialized in C
### Describe the bug
variables that are declared inside an if block are declared outside it in C and if one variable, i e  an array, depends on another variable, i e an integer, for initialization, then it will be declared erroneously.

### To Reproduce
```python
import numpy as np

class A:
    def __init__(self, x : 'int'):
        self.x = x
        self.T = np.array([1,4,6])
    @property
    def f(self):
        if self.x == 0:
            y = np.zeros(self.x)
            return y
        else:
            p = self.x
            s = 1
            n = 1
            y = np.array([np.sum(self.T[i:i+p])/p for i in range(s, s+n)])
            return y
```

### Error details
```c
array_double_1d A__f(struct A* self)
{
    int64_t p;
    int64_t s;
    int64_t n;
    int64_t i;
    int64_t Dummy_0000;
    double* y_ptr;
    double* y_ptr_0001;
    int64_t Dummy_0002;
    int64_t Dummy_0003_ptr[i + p - i];
    array_int64_1d Dummy_0003 = cspan_md_layout(c_ROWMAJOR, Dummy_0003_ptr, i + p - i);
    array_double_1d y = {0};
    if (self->x == INT64_C(0))
    {
        y_ptr = malloc(sizeof(double) * (self->x));
        y = (array_double_1d)cspan_md_layout(c_ROWMAJOR, y_ptr, self->x);
        c_foreach(Dummy_0001, array_double_1d, y) {
            *(Dummy_0001.ref) = 0.0;
        }
        return y;
    }
    else
    {
        p = self->x;
        s = INT64_C(1);
        n = INT64_C(1);
        y_ptr_0001 = malloc(sizeof(double) * (n));
        y = (array_double_1d)cspan_md_layout(c_ROWMAJOR, y_ptr_0001, n);
        Dummy_0000 = INT64_C(0);
        for (i = s; i < s + n; i += INT64_C(1))
        {
            Dummy_0002 = INT64_C(0);
            c_foreach(Dummy_0004, array_int64_1d, Dummy_0003) {
                Dummy_0002 = Dummy_0002 + (*Dummy_0004.ref);
            }
            (*cspan_at(&y, Dummy_0000)) = (double)(Dummy_0002) / (double)(p);
            Dummy_0000 = Dummy_0000 + INT64_C(1);
        }
        return y;
    }
}
```

### Expected behavior
dependent declarations should be conducted in order.

### Language
C


Pull request description:
Fix incorrect memory handling for temporary variable
Fix incorrect memory handling for temporary variable. A temporary variable created in the codegen stage was incorrectly assumed to be a scalar. Correcting this assumption fixes #2236.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 649f70cf..6c17f426 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -131,6 +131,7 @@ All notable changes to this project will be documented in this file.
 -   #2214 : Fix returning a local variable from an inline function.
 -   #1321 : Fix use of tuples returned from functions in a non-assign statement.
 -   #2229 : Fix annotation of variables that are returned in a function whose result type is annotated.
+-   #2238 : Fix incorrect memory handling for temporary variable.
 -   #2239 : Fix missing library directory for Python shared library.
 
 ### Changed
diff --git a/pyccel/codegen/printing/ccode.py b/pyccel/codegen/printing/ccode.py
index 96baec74..18f0e9fa 100644
--- a/pyccel/codegen/printing/ccode.py
+++ b/pyccel/codegen/printing/ccode.py
@@ -761,10 +761,15 @@ class CCodePrinter(CodePrinter):
             arg_var = expr.arg
             class_type = expr.arg.class_type
 
+            prefix = ''
+
             lhs = self._print(lhs_var)
             if not isinstance(arg_var, Variable):
-                tmp = self.scope.get_temporary_variable(arg_var.class_type, shape = arg_var.shape)
-                self._additional_code += self._print(Assign(tmp, arg_var))
+                # This handles slice arguments
+                assert arg_var.rank
+                tmp = self.scope.get_temporary_variable(arg_var.class_type, shape = arg_var.shape,
+                        memory_handling='alias')
+                prefix += self._print(AliasAssign(tmp, arg_var))
                 arg_var = tmp
             arg = self._print(arg_var)
             c_type = self.get_c_type(class_type)
@@ -786,7 +791,7 @@ class CCodePrinter(CodePrinter):
             body = self._additional_code + f'{lhs} = {node};\n'
             self._additional_code = tmp_additional_code
 
-            return (f'{lhs} = {start};\n'
+            return prefix + (f'{lhs} = {start};\n'
                     f'c_foreach({iter_var_name}, {c_type}, {arg}) {{\n'
                     f'{body}'
                      '}\n')


Test patch:
diff --git a/tests/epyccel/recognised_functions/test_numpy_funcs.py b/tests/epyccel/recognised_functions/test_numpy_funcs.py
index d2e08a8f..c25f3bd1 100644
--- a/tests/epyccel/recognised_functions/test_numpy_funcs.py
+++ b/tests/epyccel/recognised_functions/test_numpy_funcs.py
@@ -2454,6 +2454,21 @@ def test_sum_property(language):
     x = randint(99, size=10)
     assert f1(x) == sum_call(x)
 
+def test_sum_slice_in_if(language):
+    def sum_call(x : 'int[:]'):
+        from numpy import sum as np_sum
+        s = x.shape[0]
+        if s < 3:
+            return 0
+        else:
+            n = 1
+            m = s -1
+            return np_sum(x[n:m])
+
+    f1 = epyccel(sum_call, language = language, fflags='-Werror=uninitialized')
+    x = randint(99, size=10)
+    assert f1(x) == sum_call(x)
+
 def test_min_int(language):
     def min_call(x : 'int[:]'):
         from numpy import amin