Repository: cython/cython

Issue:
[ENH] Allow const return types
### Is your feature request related to a problem? Please describe.

Suppose I try to implement a function like

```cython
cdef const int f():
    return 1
```

Cython will generate code like
```c
static int const __pyx_f_10constrepro_f(void) {
  int const __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("f", 0);

  __pyx_r = 1;
  goto __pyx_L0;

  /* function exit code */
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
```

Since the return value was declared like `int const __pyx_r;`, `__pyx_r = 1;` is not valid.

### Describe the solution you'd like.

I would like

```cython
cdef const int f():
    return 1
```

to generate valid code.

I believe this could be accomplished by stripping const qualifiers from the declaration of the return variable, generating code like


```c
static int const __pyx_f_10constrepro_f(void) {
  int __pyx_r; // but the function return type is still `int const`
  ...
  __pyx_r = 1;
  ...
  return __pyx_r;
}
```

### Describe alternatives you've considered.

_No response_

### Additional context

_No response_


Discussion:
There's no reason why you shouldn't be able to do this and the change you propose is probably the right one. I'm not sure I understand the benefit of const return types though (except for returning const references)
I encountered this behavior while trying to implement an abstract C++ class

```cython
cdef extern from *:
    """
    class Base {
      public:
        virtual const int f() = 0;
    };
    """
    cppclass Base:
        pass

cdef cppclass Child(Base):
    int f():
        return 4
```

If I don't have the `const`, I do not successfully override `f`, but if I do have the `const`, Cython generates invalid code.
This should also apply to thinks like plain callbacks

E.g., 
```cython
from libcpp.functional cimport function

cdef g(function[const int()] h):
    pass

cdef int f():
    return 4

g(f)
```

This code isn't very realistic, but if `g` were defined externally, this would be difficult. (I think C plays fast and loose enough with function pointers that plain function pointers will not get caught on the const.)

Resolving patch:
diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py
--- a/Cython/Compiler/Nodes.py
+++ b/Cython/Compiler/Nodes.py
@@ -1999,6 +1999,11 @@ def generate_function_definitions(self, env, code):
         # Initialize the return variable __pyx_r
         init = ""
         return_type = self.return_type
+        if return_type.is_cv_qualified and return_type.is_const:
+            # Within this function body, we want to be able to set this
+            # variable, even though the function itself needs to return
+            # a const version
+            return_type = return_type.cv_base_type
         if not return_type.is_void:
             if return_type.is_pyobject:
                 init = " = NULL"


Test patch:
diff --git a/tests/run/return.pyx b/tests/run/return.pyx
--- a/tests/run/return.pyx
+++ b/tests/run/return.pyx
@@ -14,6 +14,9 @@ cdef int h(a):
     i = a
     return i
 
+cdef const int p():
+    return 1
+
 def test_g():
     """
     >>> test_g()
@@ -26,3 +29,10 @@ def test_h(i):
     5
     """
     return h(i)
+
+def test_p():
+    """
+    >>> test_p()
+    1
+    """
+    return p()