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.