---------- Forwarded message ---------
From: Marcin Jaczewski <marcinjaczewski86@gmail.com>
Date: Fri, Mar 4, 2022 at 3:06 PM
Subject: Re: [std-proposals] A new kind variable for immediate functions
To: Torben Thaysen <thaysentorben@gmail.com>
Cc: Marcin Jaczewski <marcinjaczewski86@gmail.com>


pt., 4 mar 2022 o 14:53 Torben Thaysen <thaysentorben@gmail.com> napisał(a):
>>
>> I think this should be fixed a bit diffrent way. Current `constexpr`
>> variables can materialize in result code and this is problem if we use
>> memory allocation.
>
> I am not sure what you mean. The way I understand it, whether you find some trace of constexpr variables in the final binary/assembly
> (or whether they are "materialized") is decided by the compiler the same way as for any other (inline) variable. Since what I am proposing is
> a local variable inside of immediate functions, the only place they could "materialize" is into the body of that function, which by definition doesn't
> exist at runtime.
> When you try something like
>
> consteval const int* leak_ptr() {
>     consteval int i = 1;
>     return &i;
> }
> int main() {
>     constexpr auto ptr = leak_ptr();
> }
>
> the local variable won't "materialize", instead you would get a compiler error since a pointer to an object of automatic storage duration is not
> allowed in a constant expression.
>
I mean case like:
```
int main()
{
    constexpr auto i = 5;

    return (unsigned long int)&i;
}
```
https://godbolt.org/z/Wx1v5KWjo
We have a real variable on stack with address.
This means we can't use `std::string` as it would "leak" memory from
compile time to run time and mixup life times of compilation and
runtime.
Most of the limitations of `constexpr` is because of this case.


>> One way I could see to fix it make option for "pure" `constexpr
>> variables that only live during compilation and are not accessible in
>> anyway by run time.
>
> This sounds quite similar to what I proposed but with the requirement to be in an immediate function removed. This might have the advantage
> that it could save you from having to define an extra function. However consider that with your version you are restricted to the initializer of result
> variable, which means that when the constructor you mentioned doesn't exist or you want to do something more complicated the just copy some data,
> you would have to write a helper function anyways.
>

Yes, but the difference is I make a clear distinction between what
lives at compile time and what lives at runtime. as now `constexpr`
variables can migrate between.

> Marcin Jaczewski <marcinjaczewski86@gmail.com>:
>>
>> pt., 4 mar 2022 o 12:54 Torben Thaysen via Std-Proposals
>> <std-proposals@lists.isocpp.org> napisał(a):
>> >
>> > Currently when computing things at compile time one sometimes faces a problem when trying to output the result to a constexpr variable.
>> > This happens when the result is data structure without a fixed size that utilizes dynamic memory allocation, which in itself is not a
>> > constant expression (for example a vector). Today the result can be converted to a more appropriate fixed sized structure like this:
>> >
>> > constexpr std::vector<int> compute_vector();
>> > constexpr std::size_t extract_size() { return compute_vector().size(); }
>> > constexpr auto as_array() {
>> >     auto vec = compute_vector();
>> >     std::array<int, extract_size()> arr;
>> >     std::copy(vec.begin(), vec.end(), arr.begin());
>> >     return arr;
>> > }
>> >
>> > But this somewhat awkwardly involves doing the computation twice. The only way around this is to copy the data to a large intermediate array
>> > then copy it again into an array of the right size. Neither of these solutions is really ideal and that is what this proposal aims to solve.
>> >
>> > For this I want to introduce a new kind of variable that can be declared inside an immediate function. With this the above example could look like:
>> >
>> > constexpr std::vector<int> compute_vector();
>> > consteval auto as_array() {
>> >     consteval auto vec = compute_vector(); // example syntax
>> >     std::array<int, vec.size()> arr;
>> >     std::copy(vec.begin(), vec.end(), arr.begin());
>> >     return arr;
>> > }
>> >
>> > The requirements for this type of variable should conceptually be similar to those for constexpr variables (see 9.2.6.10 and 7.7.11) except that:
>> >
>> > Targets of pointers and references don't have to have static storage duration. In particular pointers to dynamically allocated memory are allowed.
>> > Memory allocations performed in the initialization can (and must) be deallocated in the destructor.
>> > And (i think) pointers to immediate functions can also be allowed, since this type of variable only exists inside immediate functions. Although this
>> > isn't required for the aim of this proposal.
>> >
>> > To my reading this lifts all the requirements of 7.7.11 so that any core constant expression with the modified allocation requirement would be allowed.
>> > Like with constexpr variables these new variables should also be implied to be const. And I propose for consistency they should be allowed to be
>> > declared in any immediate function context as by 7.7.13 (i.e. also inside a if consteval statement).
>> >
>> > Looking forward to your feedback
>> > Torben
>> >
>> > --
>> > Std-Proposals mailing list
>> > Std-Proposals@lists.isocpp.org
>> > https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
>> I think this should be fixed a bit diffrent way. Current `constexpr`
>> variables can materialize in result code and this is problem if we use
>> memory allocation.
>> One way I could see to fix it make option for "pure" `constexpr
>> variables that only live during compilation and are not accessible in
>> anyway by run time.
>> This way we could make:
>> ```
>> int main() //can be used in any function!
>> {
>>     consteval auto s1 = std::string("Test"); //variable and memory
>> allocation live only during "compilation" of `main`, we could consider
>> this a new `static` in some way.
>>     static constexpr std::array<int, s1.size()> a1 = { s1.begin(),
>> s1.end() }; //assume that array have constructor that can copy from
>> range
>>
>>     auto s2 = std::string(s1); //Error! `s1` is not accessible here!
>>     auto s3 = std::string(a1.begin(), a1.end()); //normal string that
>> copy data from static memory
>> }
>> ```