Attempting to implement a pleasing (simple, straightforward, no TMP, no macros, no unreadable convoluted code, no weird syntax when using it) compile-time hash via user-defined literals, I found that apparently GCC's understanding of what's a constant expression is grossly different from my understanding.
Since code and compiler output say more than a thousand words, without further ado:
#include <cstdio>
constexpr unsigned int operator"" _djb(const char* const str, unsigned int len)
{
static_assert(__builtin_constant_p(str), "huh?");
return len ? str[0] + (33 * ::operator"" _djb(str+1, len-1)) : 5381;
}
int main()
{
printf("%u\n", "blah"_djb);
return 0;
}
The code is pretty straightforward, not much to explain, and not much to ask about -- except it does not evaluate at compile-time. I tried using a pointer dereference instead of using an array index as well as having the recursion break at !*str, all to the same result.
The static_assert was added later when fishing in troubled waters for why the hash just wouldn't evaluate at compile-time when I firmly believed it should. Well, surprise, that only puzzled me more, but didn't clear up anything! The original code, without the static_assert, is well-accepted and compiles without warnings (gcc 4.7.2).
Compiler output :
[...]\main.cpp: In function 'constexpr unsigned int operator"" _djb(const char*, unsigned int)':
[...]\main.cpp:5:2: error: static assertion failed: huh?
My understanding is that a string literal is, well... a literal. In other words, a compile-time constant. Specifically, it is a compiletime-known sequence of constant characters starting at a constant address assigned by the compiler (and thus, known) terminated by '\0'. This logically implies that the literal's compiler-calculated length as supplied to operator"" is a constexpr as well.
Also, my understanding is that calling a constexpr function with only compile-time parameters makes it elegible as initializer for an enumeration or as template parameter, in other words it should result in evaluation at compile time.
Of course it is in principle always allowable for the compiler to evaluate a constexpr function at runtime, but being able to move the evaluation to compile-time is the entire point of having constexpr, after all.
Where is my fallacy, and is there a way of implementing a user-defined literal that can take a string literal so it actually evaluates at compile-time?
Possibly relevant similar questions:
Can a string literal be subscripted in a constant expression?
User defined literal arguments are not constexpr?
The first one seems to suggest that at least for char const (&str)[N] this works, and GCC accepts it, though I admittedly can't follow the conclusion.
The second one uses integer literals, not string literals, and finally addresses the issue by using template metaprogramming (which I don't want). So apparently the issue is not limited to string literals?
I don't have GCC 4.7.2 at hand to try, but your code without the static assertion (more on that later) compiles fine and executes the function at compile-time with both GCC 4.7.3 and GCC 4.8. I guess you will have to update your compiler.
The compiler is not always allowed to move the evaluation to runtime: some contexts, like template arguments, and static_assert, require evaluation at compile-time or an error if not possible. If you use your UDL in a static_assert you will force the compiler to evaluate it at compile-time if possible. In both my tests it does so.
Now, on to __builtin_constant_p(str). To start with, as documented, __builtin_constant_p can produce false negatives (i.e. it can return 0 for constant expressions sometimes).
str is not provably a constant expression because it is a function argument. You can force the compiler to evaluate the function at compile-time in some contexts, but that doesn't mean it can never evaluate it at runtime: some contexts never force compile-time evaluation (and in fact, in some of those contexts compile-time evaluation is just impossible). str can be a non-constant expression.
The static assertions are tested when the compiler sees the function, not once for each call the compiler sees. That makes the fact that you always call it in compile-time contexts irrelevant: only the body matters. Because str can sometimes be a non-constant expression, __builtin_constant_p(str) in that context cannot be true: it can produce false negatives, but it does not produce false positives.
To make it more clear: static_assert(__builtin_constant_p("blah"), "") will pass (well, in theory it could be fail, but I doubt the compiler would produce a false negative here), because "blah" is always a constant expression, but str is not the same expression as "blah".
For completeness, if the argument in question was of a numeric type (more on that later), and you did the test outside of a static assertion, you could get the test to return true if you passed a constant, and false if you passed a non-constant. In a static assertion, it always fails.
But! The docs for __builtin_constant_p reveal one interesting detail:
However, if you use it in an inlined function and pass an argument of the function as the argument to the built-in, GCC will never return 1 when you call the inline function with a string constant or compound literal (see Compound Literals) and will not return 1 when you pass a constant numeric value to the inline function unless you specify the -O option.
As you can see the built-in has a limitation makes the test always return false if the expression given is a string constant.
Related
Take the following code:
template <typename T, typename U>
constexpr bool can_represent(U&& w) noexcept
{
return [] (auto&& x) {
try {
return T(std::forward<U>(x)) == std::forward<U>(x);
} catch(...) {
return false;
}
} (std::forward<U>(w));
}
I am using this function in a constant expression (template).
gcc compiles it without a problem. clang and MSVC don't, lamenting that the function does not result in a constant expression.
Indeed, gcc did not immediately accept this either; it was getting hung up on the try, that normally wouldn't be allowed in a constexpr function. That's why I had to use an immediately invoked lambda expression. However, now it works, and considering it only works with gcc I'm quite confused.
Which compiler is correct?
Is there a property of the lambda that permits this to work in a constexpr context, or is this some kind of non-standard gcc extension?
[I've used godbolt to compile with clang and MSVC, where as I have gcc 8.1.0 on my machine]
[gcc] was getting hung up on the try, that normally wouldn't be allowed in a constexpr function.
This is correct for a C++17 program. (C++20 relaxed this, so a try block can now be used in a constexpr function. However, it is only the try that is allowed; it is not allowed for execution to hit something that throws an exception.)
That's why I had to use an immediately invoked lambda expression.
The implication here is that your approach made your code valid. This is incorrect. Using an an immediately invoked lambda did not work around the problem; it swept the problem under the rug. The try is still a problem, but now compilers do not have to tell you it is a problem.
Using a lambda switches the constexpr criterion from the straight-forward "the function body must not contain a try-block" to the indirect "there exists at least one set of argument values such that an invocation of the function could be an evaluated subexpression of a core constant expression". The tricky part here is that a violation of the latter criterion is "no diagnostic required", meaning that all the compilers are correct, whether or not they complain about this code. Hence my characterization of this as sweeping the problem under the rug.
So why is... that criterion is a long thing to repeat... what's the issue involving "core constant expressions"? C++17 removed the prohibition against lambdas in core constant expressions, so that much looks good. However, there is still a requirement that all function calls within the constexpr function also be themselves constexpr. Lambdas can become constexpr in two ways. First, they can be explicitly marked constexpr (but if you do that here, the complaint about the try block should come back). Second, they can simply satisfy the constexpr function requirements. However, your lambda contains a try, so it is not constexpr (in C++17).
Your lambda is not a valid constexpr function. Hence calling it is not allowed in a core constant expression. There is no execution path through can_represent() that avoids invoking your lambda. Therefore, can_represent is not a valid constexpr function, no diagnostic required.
Coverity has complained that various function calls in our codebase are not checking the return value.
Unchecked return value (CHECKED_RETURN)3. check_return: Calling Append
without checking return value (as is done elsewhere 73 out of 78
times).
In the past, we would have simply resolved this issue (after double-checking that the return value really was not important) by casting the return to void (as discussed here):
(void)Foo.Append(bar);
However, we are moving towards enabling all warnings, and treating warnings as errors, so I'm a little concerned that the above code will generate an old-style-cast diagnostic. If that's the case, I will need to modify our code to the considerably uglier format:
static_cast<void>( Foo.Append(bar) );
However, both gcc and clang seem to be able to compile this code (the first form) without complaining. So I suppose the final form of my question is this: Is casting a function return to void considered an exception to the rule as far as C-style casts are concerned? Or do I need to double check my code and see if the lines in question aren't actually being included in those builds?
It's fine.
(void) f(x);
is always equivalent to a static_cast as per [expr.static.cast]/6:
Any expression can be explicitly converted to type cv void, in which case it becomes a discarded-value expression.
Converting the result of a function to void is the way to make an expression a discard-value-expression. Now, the C++ way should be static_cast<void>(...)but (void) ... is an idiom (and is shorter).
Since the latter is well-defined and really common in codebases, gcc1 and clang2 made it not trigger Wold-style-cast.
It's well-defined, recognized by major compilers. It's fine.
1) g++ documentation --- 3.5 Options Controlling C++ Dialect
-Wold-style-cast (C++ and Objective-C++ only)
Warn if an old-style (C-style) cast to a non-void type is used within a C++ program. The new-style casts (dynamic_cast, static_cast, reinterpret_cast, and const_cast) are less vulnerable to unintended effects and much easier to search for.
2) not documented
I have a piece of code that looks like this:
constexpr gsl::cstring_span<> const somestring{"Hello, I am a string"};
and it refuses to compile with a message complaining that some non-constexpr function is being called somewhere.
Why is this? This seems like the most important use-case to support. The whole point is to have compile-time bounds checking if at all possible. Compile time bounds checking involving constant string literals seems like the thing it would be used for the most often. But this can't happen if it can't be declared constexpr. What's going on here?
I think the problem is that string literals have type array of const char and are null-terminated. But who is to say you are constructing your cstring_span from a null-terminated array?
Because of that the constructor of cstring_span does a physical check to remove the null terminator if it exists, otherwise accept the full length of the array.
I am not sure how powerful constexpr expressions can be but it may be possibly to implement it in a constexpr way. You could create an issue asking about it here:
https://github.com/Microsoft/GSL/issues
I have a code like this
const int Value = 123 * 2 + GetOffset();
GetOffset is a constexpr function returning int.
How can I make sure this expression is indeed evaluated at compile time?
Why don't you use constexpr for Value too? I think it will ask the compiler to evaluate it,
constexpr int Value = 123 * 2 + GetOffset();
if the function GetOffset() is simple and meet the requirements of constexpr.
The requirements are
the function must have a non-void return type.
the function body cannot declare variables or define new types.
the body may contain only declarations, null statements and a single return
statement.
Since Getoffset() returns int, it meets the first one.
You can't ensure the compiler does this. You generally need to enable optimization, including some level of function inlining. What these options are depend on your compiler and its version.
You can check the generated assembly to see if it contains a call to GetOffset or just uses a constant determined by the compiler.
what if you declare 'Value' as constexpr too? Actually you can probalby never be sure if something is evaluated at compilation time, however in this case there is no reason why it could not be evaluated.
One possibility is to use std::ratio. From section 20.10.1 of the C++11 standard:
This subclause describes the ratio library. It provides a class template ratio which exactly represents any finite rational number with a numerator and denominator representable by compile-time constants of type intmax_t.
So according to the standard, this would only be valid for a compile-time constant:
const int value = std::ratio<123 * 2 + GetOffset()>::num;
So this would guarantee that the expression is evaluated at compile time. However, it doesn't also guarantee that the expression is not evaluated at run time.
You can't be absolutely sure; the compiler is only required to generate code with the specified behaviour, and calculating it at compile- or run-time would not change the behaviour.
However, the compiler is required to be able to evaluate this at compile time, since it can be used where only compile-time constants are allowed such as array sizes and template arguments; so there's no reason why a sane compiler shouldn't perform that obvious optimisation. If the compiler doesn't (at least with optimisations enabled), throw it away and find a better one.
You can check the assembly produced by the compiler to see whether it calculates the value; but this in itself doesn't guarantee that future builds will do the same.
Considering that I have not used C++ in over half a decade now, the chances of the suggestion being way of the mark are quite high, but what about using inline for the function.
If the function returns a certain predefined value, available at the compile time, then the compiler should be able to make use of that value.
Create a separate source file with the expression. Evaluate printf("#define MyExpression %d.\n", expression);. When building your project, compile this source file for the native system and execute it. Include the resulting output as a header in your regular sources.
If you want to confirm that the initializer is a constant expression than you can use the constexpr specifier:
constexpr int Value = 123 * 2 + GetOffset();
It will fail to compile if it isn't a constant expression.
It is theoretically unspecified whether a constexpr variable Value is actually calculated during translation - but in practice you can be sure it is.
Just assert it: static_assert(Value == 123 * 2 + GetOffset(), "constexpr");
Doesn't get any simpler than that.
After some search for a way to check endianess at compile-time I've come up with the following solution:
static const int a{1};
constexpr bool is_big_endian()
{
return *((char*)&(a)) == 1;
}
GCC accepts this code only in some contexts where constexpr is required:
int b[is_big_endian() ? 12 : 25]; //works
std::array<int, testendian() ? 12 : 25> c; //fails
For the second case, GCC says error: accessing value of ‘a’ through a ‘char’ glvalue in a constant expression. I couldn't find anything in the standard that forbids such thing. Maybe someone could clarify in which case GCC is correct?
This is what I get from Clang 3.1 ToT:
error: constexpr function never produces a constant expression
§5.19 [expr.const]
p1 Certain contexts require expressions that satisfy additional requirements as detailed in this sub-clause; other contexts have different semantics depending on whether or not an expression satisfies these requirements. Expressions that satisfy these requirements are called constant expressions.
p2 A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression:
[...]
a reinterpret_cast (5.2.10);
So, (char*)&(a) evaluates to a reinterpret_cast, as such the function is never a valid constexpr function.
You should look into Boost.Detail.Endian
It is a mapping of several architectures to their endianness (through the macros BOOST_BIG_ENDIAN, BOOST_LITTLE_ENDIAN, and BOOST_PDP_ENDIAN). As far as I know, there is no actual way to determine the endianness at compile time, other than a list like this.
For an example implementation that uses Boost.Detail.Endian, you can see the library I'm hoping to get reviewed for submission to Boost: https://bitbucket.org/davidstone/endian/ (the relevant file is byte_order.hpp, but unsigned.hpp is necessary as well if you want to just use my implementation).
If N3620 - Network Byte Order Conversion is implemented, you'll be able to use the constexpr ntoh to check for endianness, but remember there are rare architectures like middle-endian and you'll never be able to support all of them.