What does it mean to "poison a function" in C++? - c++

At the very end of Scott Schurr's talk "Introducing constexpr" at CppCon, he asks "Is there a way to poison a function"? He then explains that this can be done (albeit in a non-standard way) by:
Putting a throw in a constexpr function
Declaring an unresolved extern const char*
Referencing the unresolved extern in the throw
I sense that I'm a bit out of my depth here, but I'm curious:
What does it mean to "poison a function"?
What is the significance/usefulness of the technique he outlines?

In general it refers to making a function unusable, e.g. if you want to ban the use of dynamic allocation in a program you could "poison" the malloc function so it can't be used.
In the video he's using it in a more specific way, which is clear if you read the slide that is displayed when he talks about poisoning the function, which says "A way to force compile-time only?"
So he is talking about "poisoning" the function to make it uncallable at run-time, so it's only callable in constant expressions. The technique is to have a branch in the function which is never taken when called in a compile-time context, and to make that branch contain something that will cause an error.
A throw expression is allowed in a constexpr function, as long as it is never reached during compile-time invocations of the function (because you can't throw an exception at compile-time, it's an inherently dynamic operation, like allocating memory). So a throw expression that refers to an undefined symbol will not be used during compile-time invocations (because that would fail to compile) and cannot be used at run-time, because the undefined symbol causes a linker error.
Because the undefined symbol is not "odr-used" in the compile-time invocations of the function, in practice the compiler will not create a reference to the symbol, so it's OK that it's undefined.
Is that useful? He's demonstrating how to do it, not necessarily saying it's a good idea or widely useful. If you have a need to do it for some reason then his technique might solve your problem. If you don't have a need for it, you don't need to worry about it.
One reason it might be useful is when the compile-time version of some operation is not as efficient as it could be. There are restrictions on the kind of expressions allowed in a constexpr function (especially in C++11, some restrictions were removed in C++14). So you might have two versions of a function for performing a calculation, one that is optimal, but uses expressions that aren't allowed in a constexpr function, and one that is a valid constexpr function, but would perform poorly if called at run-time. You could poison the sub-optimal one to ensure it is never used for run-time calls, ensuring the more efficient (non-constexpr) version is used for run-time calls.
N.B. The performance of a constexpr function used at compile-time is not really important, because it has no run-time overhead anyway. It might slow down your compilation by making the compiler do extra work, but it won't have any run-time performance cost.

'Poisoning' an identifier means that any reference to the identifier after the 'poisoning' is a hard compiler error. This technique may be used, for instance, for hard deprecation (function IS deprecated, never use it!).
In GCC traditionally there was a pragma for this: #pragma GCC poison.

Related

c++ why do constexpr functions need to be marked constexpr? [duplicate]

To the best of my knowledge, the inline keyword in c++ can be traced back to old compilers (then known as "optimizing compilers") not being able to optimize as well as modern ones, so marking a function as inline told the compiler that this should be inlined, and as a side effect prevented ODR issues. As compilers got better, someone realized that the compilers can do a much better job of optimizing than the programmer, and so the inline requirement of the compiler became more of a 'hint' that most (all?) modern compilers ignore.
Enter C++11 and subsequent versions. constexpr seems to me to be in a similar situation, at least for some of its uses, specifically functions and variables. As I understand it, it tells the compiler that a certain function may be evaluated at compile time. But that is something the compiler should be able to figure out on its own. Is this feature also going to become a 'hint' once compilers get better at optimizing?
Note: I am not asking about other uses of constexpr, such as with if statements. I understand those are needed.
As I understand it, it tells the compiler that a certain function may be evaluated at compile time.
Not "may", but "can". The constexpr keyword does not tell the compiler what it is allowed to do (it may evaluate anything it wants at compile time). Rather the keyword tells the compiler a desired quality of the variable or function, specifically that it can be used in constant expressions. The compiler will complain (error or warning) if the program fails to live up to that desire. You get a more relevant error message than you would have gotten otherwise – the compiler can tell you why your entity does not qualify for compile-time evaluation since it knows that your intent was for the entity to be a compile-time constant.
For example, if you defined const unsigned a, it is an error to use std::array<int, a> if the value of a is not known at compile time. The error might be in the initialization of a, or it might be that the template parameter was supposed to be b instead of a. The compiler would have to report the error as "a is not a constant expression" and let the programmer investigate. On the other hand, if a was declared constexpr, the compiler would instead complain about the reason the value of a is not known at compile time, leading to less time debugging.
Without constexpr, the following code produces a possibly weak error message.
{
const unsigned a = foo();
const unsigned b = 42;
std::array<int, a> stuff; // Error: 'a' is not a constant expression.
// ...
}
After declaring both a and foo() to be constexpr, the error disappears. Why? Because last week when you wrote foo(), the compiler was told that the function had to be usable in constant expressions. As a result, the compiler pointed out why foo() could not be evaluated at compile time, and you fixed the bug right away. That was last week, while the implementation of foo() was still fresh in your mind. Not this week, after doing a dozen other things, including the hour spent arguing with the compiler because you believed a had to be a constant expression since it was initialized with foo().
An ideal compiler could maybe figure out which functions are actually constexprand in that sense one could view that keyword as a hint to the compiler.
But I think it makes more sense to compare const and constexpr in terms of what they tell the compiler and the human reader. An ideal compiler could also figure out, which variables and member functions should be const. As you probably know, there are other good reasons to mark everything possible const (compiler finds bugs for you, much easier to read, helps the compiler in optimization).
The same is true for constexpr. If you declare a variable constexpr, that cannot be computed at compile time, you get an error, you have documented that the variable can be computed at compile time and it helps the compiler in optimization.
Also note that ignoring constexpr does not make sense for runtime performance, which is not true for inline.
But that is something the compiler should be able to figure out on its
own. Is this feature also going to become a 'hint' once compilers get
better at optimizing?
constexpr is not merely an optimization - without
it, the compiler is not allowed to use a function in contexts where a constant expression is required, e.g. in non-type template arguments.
But I am sure you already know that much. The real question is: should a future C++ standard allow using a function in constant expression context even though it is not explicitly marked constexpr - in case if it satisfies contexpr requirements?
No, I think it is the opposite direction from C++ development. Consider C++20 concept. One of its major goals is to improve error messages: instead of going through nested template definitions, the compiler knows early that the template argument does not meet a requirement. Keyword constexpr serves the same goal: the compiler, instead of going through a function call tree and finding that a function deep in the call stack cannot be evaluated at compile-time, reports the error early.

Is constexpr the new inline?

To the best of my knowledge, the inline keyword in c++ can be traced back to old compilers (then known as "optimizing compilers") not being able to optimize as well as modern ones, so marking a function as inline told the compiler that this should be inlined, and as a side effect prevented ODR issues. As compilers got better, someone realized that the compilers can do a much better job of optimizing than the programmer, and so the inline requirement of the compiler became more of a 'hint' that most (all?) modern compilers ignore.
Enter C++11 and subsequent versions. constexpr seems to me to be in a similar situation, at least for some of its uses, specifically functions and variables. As I understand it, it tells the compiler that a certain function may be evaluated at compile time. But that is something the compiler should be able to figure out on its own. Is this feature also going to become a 'hint' once compilers get better at optimizing?
Note: I am not asking about other uses of constexpr, such as with if statements. I understand those are needed.
As I understand it, it tells the compiler that a certain function may be evaluated at compile time.
Not "may", but "can". The constexpr keyword does not tell the compiler what it is allowed to do (it may evaluate anything it wants at compile time). Rather the keyword tells the compiler a desired quality of the variable or function, specifically that it can be used in constant expressions. The compiler will complain (error or warning) if the program fails to live up to that desire. You get a more relevant error message than you would have gotten otherwise – the compiler can tell you why your entity does not qualify for compile-time evaluation since it knows that your intent was for the entity to be a compile-time constant.
For example, if you defined const unsigned a, it is an error to use std::array<int, a> if the value of a is not known at compile time. The error might be in the initialization of a, or it might be that the template parameter was supposed to be b instead of a. The compiler would have to report the error as "a is not a constant expression" and let the programmer investigate. On the other hand, if a was declared constexpr, the compiler would instead complain about the reason the value of a is not known at compile time, leading to less time debugging.
Without constexpr, the following code produces a possibly weak error message.
{
const unsigned a = foo();
const unsigned b = 42;
std::array<int, a> stuff; // Error: 'a' is not a constant expression.
// ...
}
After declaring both a and foo() to be constexpr, the error disappears. Why? Because last week when you wrote foo(), the compiler was told that the function had to be usable in constant expressions. As a result, the compiler pointed out why foo() could not be evaluated at compile time, and you fixed the bug right away. That was last week, while the implementation of foo() was still fresh in your mind. Not this week, after doing a dozen other things, including the hour spent arguing with the compiler because you believed a had to be a constant expression since it was initialized with foo().
An ideal compiler could maybe figure out which functions are actually constexprand in that sense one could view that keyword as a hint to the compiler.
But I think it makes more sense to compare const and constexpr in terms of what they tell the compiler and the human reader. An ideal compiler could also figure out, which variables and member functions should be const. As you probably know, there are other good reasons to mark everything possible const (compiler finds bugs for you, much easier to read, helps the compiler in optimization).
The same is true for constexpr. If you declare a variable constexpr, that cannot be computed at compile time, you get an error, you have documented that the variable can be computed at compile time and it helps the compiler in optimization.
Also note that ignoring constexpr does not make sense for runtime performance, which is not true for inline.
But that is something the compiler should be able to figure out on its
own. Is this feature also going to become a 'hint' once compilers get
better at optimizing?
constexpr is not merely an optimization - without
it, the compiler is not allowed to use a function in contexts where a constant expression is required, e.g. in non-type template arguments.
But I am sure you already know that much. The real question is: should a future C++ standard allow using a function in constant expression context even though it is not explicitly marked constexpr - in case if it satisfies contexpr requirements?
No, I think it is the opposite direction from C++ development. Consider C++20 concept. One of its major goals is to improve error messages: instead of going through nested template definitions, the compiler knows early that the template argument does not meet a requirement. Keyword constexpr serves the same goal: the compiler, instead of going through a function call tree and finding that a function deep in the call stack cannot be evaluated at compile-time, reports the error early.

What are the advantages of using consteval instead of constexpr function?

I know the difference in requirements, I am mostly interested in what benefits from code quality it brings.
Few things I can think of:
reader can just read the function signature and know that function is evaluated at compile time
compiler may emit less code since consteval fns are never used at runtime(this is speculative, I have no real data on this)
no need to have variables to force ctfe, example at the end
note: if code quality is too vague I understand some people might want to close this question, for me code quality is not really that vague term, but...
example where constexpr failure is delayed to runtime:
constexpr int div_cx(int a, int b)
{
assert(b!=0);
return a/b;
}
int main()
{
static constexpr int result = div_cx(5,0); // compile time error, div by 0
std::cout << result;
std::cout << div_cx(5,0) ; // runtime error :(
}
In order to have meaningful, significant static reflection (reflection at compile time), you need a way to execute code at compile time. The initial static reflection TS proposal used traditional template metaprogramming techniques, because those were the only effective tools for executing code at compile-time at all.
However, as constexpr code gained more features, it became increasingly more feasible to do compile-time static reflection through constexpr functions. One problem with such ideas is that static reflection values cannot be allowed to leak out into non-compile-time code.
We need to be able to write code that must only be executed at compile-time. It's easy enough to do that for small bits of code in the middle of a function; the runtime version of that code simply won't contain the reflection parts, only the results of them.
But what if you want to write a function that takes a reflection value and returns a reflection value? Or a list of reflection values?
That function cannot be constexpr, because a constexpr function must be able to be executed at runtime. You are allowed to do things like get pointers to constexpr functions and call them in ways that the compiler can't trace, thus forcing it to execute at runtime.
A function which takes a reflection value can't do that. It must execute only at compile-time. So constexpr is inappropriate for such functions.
Enter consteval: a function which is "required" to execute only at compile time. There are specific rules in place that make it impossible for pointers to such functions to leak out into runtime code and so forth.
As such, consteval doesn't have much purpose at the moment. It gets used in a few places like source_location::current(), which fundamentally makes no sense to execute at runtime. But ultimately, the feature is a necessary building-block for further compile-time programming tools that don't exist yet.
This was laid down in the paper that originally proposed this feature:
The impetus for the present paper, however, is the work being done by SG7 in the realm of compile-time reflection. There is now general agreement that future language support for reflection should use constexpr functions, but since "reflection functions" typically have to be evaluated at compile time, they will in fact likely be immediate functions.

Is compiler allowed to call an immediate (consteval) function during runtime?

This might be a stupid question, but I am confused. I had a feeling that an immediate (consteval) function has to be executed during compile time and we simply cannot see its body in the binary.
This article clearly supports my feeling:
This has the implication that the [immediate] function is only seen at compile time. Symbols are not emitted for the function, you cannot take the address of such a function, and tools such as debuggers will not be able to show them. In this matter, immediate functions are similar to macros.
The similar strong claim might be found in Herb Sutter's publication:
Note that draft C++20 already contains part of the first round of reflection-related work to land in the standard: consteval functions that are guaranteed to run at compile time, which came from the reflection work and are designed specifically to be used to manipulate reflection information.
However, there is a number of evidences that are not so clear about this fact.
From cppreference:
consteval - specifies that a function is an immediate function, that is, every call to the function must produce a compile-time constant.
It does not mean it has to be called during compile time only.
From the P1073R3 proposal:
There is now general agreement that future language support for reflection should use constexpr functions, but since "reflection functions" typically have to be evaluated at compile time, they will in fact likely be immediate functions.
Seems like this means what I think, but still it is not clearly said. From the same proposal:
Sometimes, however, we want to express that a function should always produce a constant when called (directly or indirectly), and a non-constant result should produce an error.
Again, this does not mean the function has to be evaluated during compile time only.
From this answer:
your code must produce a compile time constant expression. But a compile time constant expression is not an observable property in the context where you used it, and there are no side effects to doing it at link or even run time! And under as-if there is nothing preventing that
Finally, there is a live demo, where consteval function is clearly called during runtime. However, I hope this is due to the fact consteval is not yet properly supported in clang and the behavior is actually incorrect, just like in Why does a consteval function allow undefined behavior?
To be more precise, I'd like to hear which of the following statements of the cited article are correct:
An immediate function is only seen at compile time (and cannot be evaluated at run time)
Symbols are not emitted for an immediate function
Tools such as debuggers will not be able to show an immediate function
To be more precise, I'd like to hear which of the following statements of the cited article are correct:
An immediate function is only seen at compile time (and cannot be evaluated at run time)
Symbols are not emitted for an immediate function
Tools such as debuggers will not be able to show an immediate function
Almost none of these are answers which the C++ standard can give. The standard doesn't define "symbols" or what tools can show. Almost all of these are dealer's choice as far as the standard is concerned.
Indeed, even the question of "compile time" vs. "run time" is something the standard doesn't deal with. The only question that concerns the standard is whether something is a constant expression. Invoking a constexpr function may produce a constant expression, depending on its parameters. Invoking a consteval function in a way which does not produce a constant expression is il-formed.
The one thing the standard does define is what gets "seen". Though it's not really about "compile time". There are a number of statements in C++20 that forbid most functions from dealing in pointers/references to immediate functions. For example, C++20 states in [expr.prim.id]/3:
An id-expression that denotes an immediate function shall appear only
as a subexpression of an immediate invocation, or
in an immediate function context.
So if you're not in an immediate function, or you're not using the name of an immediate function to call another immediate function (passing a pointer/reference to the function), then you cannot name an immediate function. And you can't get a pointer/reference to a function without naming it.
This and other statements in the spec (like pointers to immediate function not being valid results of constant expressions) essentially make it impossible for a pointer/reference to an immediate function to leak outside of constant expressions.
So statements about the visibility of immediate functions are correct, to some degree. Symbols can be emitted for immediate functions, but you cannot use immediate functions in a way that would prevent an implementation from discarding said symbols.
And that's basically the thing with consteval. It doesn't use standard language to enforce what must happen. It uses standard language to make it impossible to use the function in a way that will prevent these things from happening. So it's more reasonable to say:
You cannot use an immediate function in a way that would prevent the compiler from executing it at compile time.
You cannot use an immediate function in a way that would prevent the compiler from discarding symbols for it.
You cannot use an immediate function in a way that would force debuggers to be able to see them.
Quality of implementation is expected to take things from there.
It should also be noted that debugging builds are for... debugging. It would be entirely reasonable for advanced compiler tools to be able to debug code that generates constant expressions. So a debugger which could see immediate functions execute is an entirely desirable technology. This becomes moreso as compile-time code grows more complex.
The proposal mentions:
One consequence of this specification is that an immediate function never needs to be seen by a back end.
So it is definitely the intention of the proposal that calls are replaced by the constant. In other words, that the constant expression is evaluated during translation.
However, it does not say it is required that it is not seen by the backend. In fact, in another sentence of the proposal, it just says it is unlikely:
It also means that, unlike plain constexpr functions, consteval functions are unlikely to show up in symbolic debuggers.
More generally, we can re-state the question as:
Are compilers forced to evaluate constant expressions (everywhere; not just when they definitely need it)?
For instance, a compiler needs to evaluate a constant expression if it is the number of elements of an array, because it needs to statically determine the total size of the array.
However, a compiler may not need to evaluate other uses, and while any decent optimizing compiler will try to do so anyway, it does not mean it needs to.
Another interesting case to think about is an interpreter: while an interpreter still needs to evaluate some constant expressions, it may just do it lazily all the time, without performing any constant folding.
So, as far as I know, they aren't required, but I don't know the exact quotes we need from the standard to prove it (or otherwise). Perhaps it is a good follow-up question on its own, which would answer this one too.
For instance, in [expr.const]p1 there is a note that says they can, not that they are:
[Note: Constant expressions can be evaluated during translation. — end note]

Why is constexpr not automatic? [duplicate]

This question already has answers here:
Why do we need to mark functions as constexpr?
(4 answers)
Closed 2 years ago.
As far as I understand it, constexpr can be seen as a hint to the compiler to check whether given expressions can be evaluated at compile-time and do so if possible.
I know that it also imposes some restriction on the function or initialization declared as constexpr but the final goal is compile-time evaluation, isn't it?
So my question is, why can't we leave that at the compiler? It is obviously capable of checking the pre-conditions, so why doesn't it do for each expression and evaluate at compile-time where possible?
I have two ideas on why this might be the case but I am not yet convinced that they hit the point:
a) It might take too long during compile-time.
b) Since my code can use constexpr functions in locations where normale functions would not be allowed the specifier is also kind of part of the declaration. If the compiler did everything by itself, one could use a function in a C-array definition with one version of the function but with the next version there might be a compiler-error, because the pre-conditions for compile-time evaluation are no more satisfied.
constexpr is not a "hint" to the compiler about anything; constexpr is a requirement. It doesn't require that an expression actually be executed at compile time; it requires that it could.
What constexpr does (for functions) is restrict what you're allowed to put into function definition, so that the compiler can easily execute that code at compile time where possible. It's a contract between you the programmer and the compiler. If your function violates the contract, the compiler will error immediately.
Once the contract is established, you are now able to use these constexpr functions in places where the language requires a compile time constant expression. The compiler can then check the elements of a constant expression to see that all function calls in the expression call constexpr functions; if they don't, again a compiler error results.
Your attempt to make this implicit would result in two problems. First, without an explicit contract as defined by the language, how would I know what I can and cannot do in a constexpr function? How do I know what will make a function not constexpr?
And second, without the contract being in the compiler, via a declaration of my intent to make the function constexpr, how would the compiler be able to verify that my function conforms to that contract? It couldn't; it would have to wait until I use it in a constant expression before I find that it isn't actually a proper constexpr function.
Contracts are best stated explicitly and up-front.
constexpr can be seen as a hint to the compiler to check whether given expressions can be evaluated at compile-time and do so if possible
No, see below
the final goal is compile-time evaluation
No, see below.
so why doesn't it do for each expression and evaluate at compile-time where possible?
Optimizers do things like that, as allowed under the as-if rule.
constexpr is not used to make things faster, it is used to allow usage of the result in context where a runtime-variable expression is illegal.
This is only my evaluation, but I believe your (b) reason is correct (that it forms part of the interface that the compiler can enforce). The interface requirement serves both for the writer of the code and the client of the code.
The writer may intend something to be usable in a compile-time context, but not actually use it in this way. If the writer violates the rules for constexpr, they might not find out until after publication when clients who try to use it constexpr fail. Or, more realistically, the library might use the code in a constexpr sense in version 1, refactor this usage out in version 2, and break constexpr compatibility in version 3 without realizing it. By checking constexpr-compliance, the breakage in version 3 will be caught before deployment.
The interface for the client is more obvious --- an inline function won't silently become constexpr-required because it happened to work and someone used that way.
I don't believe your (a) reason (that it could take too long for the compiler) is applicable because (1) the compiler has to check much of the constexpr constraints anyway when the code is marked, (2) without the annotation, the compiler would only have to do the checking when used in a constexpr way (so most functions wouldn't have to be checked), and (3) IIUC the D programming language actually does allow functions to be compile-time evaluated if they meet requirements without any declaration assistance, so apparently it can be done.
I think I remember watching an early talk by Bjarne Stroustrup where he mentioned that programmers wanted fine grained control on this "dangerous" feature, from which I understand that they don't want things "accidentally" executed at compile time without them knowing. (Even if that sound like a good thing.)
There can be many reasons for that, but the only valid one is ultimatelly compilation speed I think ( (a) in your list ).
It would be too much burden on the compiler to determine for every function if it could be computed at compile time.
This argument is weaker as compilation times in general go down.
Like many other features of C++ what end up happening is that we end up with the "wrong defaults".
So you have to tell when you want constexpr instead of when you don't want constexpr (runtimeexpr); you have to tell when you want const intead of where you want mutable, etc.
Admitedly, you can imagine functions that take an absurd amount of time to run at compile time and that cannot be amortized (with other kind of machine resources) at runtime.
(I am not aware that "time-out" can be a criterion in a compiler for constexpr, but it could be so.)
Or it could be that one is compiling in a system that is always expected to finish compilation in a finite time but an unbounded runtime is admissible (or debuggable).
I know that this question is old, but time has illuminated that it actually makes sense to have constexpr as default:
In C++17, for example, you can declare a lambda constexpr but more importantly they are constexpr by default if they can be so.
https://learn.microsoft.com/en-us/cpp/cpp/lambda-expressions-constexpr
Note that lambda has all the "right" (opposite) defaults, members (captures) are const by default, arguments are templates by default auto, and now these functions are constexpr by default.