6

The following compiles in GCC but not in Clang:

#include <cstring>

constexpr int test = strcmp("test", "test");

So my question is, how does GCC handle strcmp differently to make this possible? Is strcmp some type of builtin, or does its standard library have a non-standard definition of strcmp that includes constexpr?

Chris_F
  • 4,991
  • 5
  • 33
  • 63

2 Answers2

6

The code compiles on gcc because it provides a built-in version of strcmp that is evaluated at compile time, assuming you pass string literals to the function.

gcc will reject the code if you pass the -fno-builtin (or -fno-builtin-strcmp) flag.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • It seems that Clang has a `__builtin_strcmp` as well, but it is cannot be used in a constexpr like GCC's. – Chris_F Jul 02 '14 at 00:17
  • 1
    @Chris_F IMHO gcc's behavior is a bug; when used in a `constexpr` expression, it should be checking whether the stdlib version of the function is `constexpr` prior to replacing it with the built-in. Maybe the right behavior would've been that `-std=c++11` rejects the code by default, but `-std=gnu++11` accepts it? Can't seem to file an existing bug report on the matter. – Praetorian Jul 02 '14 at 00:24
  • It seems like this may be the case for many other builtins as well. For instance, in GCC `__builtin_sin` can be used in a constexpr, but in Clang it cannot. – Chris_F Jul 02 '14 at 00:52
  • It seems like you should be able to use things like sin and sqrt in a constexpr ideally. – Chris_F Jul 02 '14 at 00:53
  • 1
    @Chris_F that's debatable... there's a similar years-long debate about whether templates should allow floating point parameters that has the same set of potential issues - e.g. the compiler's calculation of a floating point expression may differ from runtime evaluation of the same expression (on other hardware, or due to different optimisation or register usage) and/or compile time evaluation by another compiler, causing things like comparisons to fail in weird ways. Walter Bright allows it for templates in D, but I suspect he's wants differentiating features more than portability 8-?. – Tony Delroy Jul 02 '14 at 01:15
  • @TonyD: The problem is that floating-point operations aren't pure -- their results are the return value... and FPU status word, and maybe even a runtime hardware exception. Moving those globally-visible side effects to compile time violates the as-if rule. Now, for some parameters, no such side effects occur. But in the general case, floating-point operations can't be precomputed. – Ben Voigt Dec 01 '15 at 04:25
  • @BenVoigt: integer arithmetic also changes other CPU flags (carry, zero etc) - the compiler can allow for that and still operate under the as-if rule, and could equally do so for floating point operations; similarly, integer divide by 0 also often generates a hardware exception. So - I still believe the accuracy factors I mentioned earlier are the main concerns, though certainly differences in accuracy could result in an exception at compile time where one wouldn't have happened at runtime, or vice versa, but as either behaviour was equally "correct" who cares? – Tony Delroy Dec 01 '15 at 04:58
3

Nothing forbids a function from being constexpr. There's just no guarantee that strcmp is constexpr. A good compiler will probably be able to perform string operations on compile-time constant strings efficiently, but that's an implementation detail.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • I'm not sure I understand fully. You are saying that the spec says that the compiler is free to treat a function that is not marked `constexpr` as if it were? – Chris_F Jul 01 '14 at 23:54
  • 1
    @Chris_F: Well, yes - it's not an observable property of a non-`constexpr` function to be `constexpr`. – Kerrek SB Jul 01 '14 at 23:55
  • 4
    c++14 forbids it "An implementation shall not declare any standard library function signature as constexpr except for those where it is explicitly required" -- `17.6.5.6[constexpr.functions]/1` – Cubbi Jul 02 '14 at 02:21
  • @Cubbi: And indeed, the implementation *did not* declare `strcmp` as `constexpr`! That was my whole point. – Kerrek SB Jul 02 '14 at 09:34
  • 1
    @KerrekSB Are you suggesting that the compiler is free to turn a function call expression into a constant expression if the function isn't declared constexpr? That violates `5.19[expr.const]/2`. The point of disallowing constexpr library functions in the first place was to prevent unexpectedly const behavior: "users may use SFINAE to observe different behavior from otherwise identical code": [LWG 2013](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2013) – Cubbi Jul 02 '14 at 12:45
  • 1
    @Cubbi: How would you be able to observe the difference? If the function isn't declared `constexpr`, you cannot validly call it in a place where a constant expression is required. The fact that something works that isn't guaranteed to work isn't a violation, is it? – Kerrek SB Jul 02 '14 at 12:59
  • 3
    The rationale talks about SFINAE. Granted, it's not likely that someone would set up a `template`, it may make more sense with other library functions. As far as I can tell, gcc is non-conforming post-LWG 2013. – Cubbi Jul 02 '14 at 13:58
  • @Cubbi: that example would be ill-formed, since `strcmp` isn't declared `constexpr`, so it doesn't constitute observable behaviour, non? – Kerrek SB Jul 02 '14 at 14:26
  • 2
    @KerrekSB It would be removed from the overload set (on a conforming implementation) – Cubbi Jul 02 '14 at 14:43
  • @Cubbi: Interesting. Is that actually an allowed SFINAE context, or would that in fact be a hard error? – Kerrek SB Jul 02 '14 at 20:21