C++ Logo

std-proposals

Advanced search

[std-proposals] Fwd: A new kind variable for immediate functions

From: Torben Thaysen <thaysentorben_at_[hidden]>
Date: Sat, 5 Mar 2022 08:59:49 +0100
---------- Forwarded message ---------
From: Torben Thaysen <thaysentorben_at_[hidden]>
Date: Fri, Mar 4, 2022 at 4:02 PM
Subject: Re: [std-proposals] A new kind variable for immediate functions
To: <marcinjaczewski86_at_[hidden]>


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.
>
That is why I made the restriction to consteval functions. There shouldn't
be any way to leak the address of a local variable inside a consteval
function to
runtime code. The same is true for any intermediate object created during
the evaluation of a constant expression. Otherwise we couldn't even use
vector/string as regular variables in constant expressions. For example

consteval auto foo() {
    std::string s("Test");
    return s.size();
}

is clearly valid and there better be no way to leak the memory allocated by
"s" to runtime. And that doesn't change when we make "s" a "consteval"
variable.

Marcin Jaczewski <marcinjaczewski86_at_[hidden]>:

> pt., 4 mar 2022 o 14:53 Torben Thaysen <thaysentorben_at_[hidden]>
> 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_at_[hidden]>:
> >>
> >> pt., 4 mar 2022 o 12:54 Torben Thaysen via Std-Proposals
> >> <std-proposals_at_[hidden]> 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_at_[hidden]
> >> > 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
> >> }
> >> ```
>

Received on 2022-03-05 08:00:01