Hacker News new | ask | show | jobs
by simiones 1168 days ago
That only works if you know the values at compile-time though:

  constexpr int foo(int x) {
    return 1024*1024*1024*x;
  }
  
  int main()
  {
    int y;
    std::cin >> y;
    static_assert(foo(1));  //all good
    foo(y);                 //oops, UB if user enters 7
  }
https://godbolt.org/z/K8h4Kj99s

Edit: small correction so that the numbers are big enough to cause problems...

2 comments

Yeah, the tests will only fail if the tests trigger UB. It's like all testing, it only detects issues if you trigger the issues in the tests. Using static_assert as your test system obviously doesn't obviate the need for writing good tests.
Many people in this thread think that if a constexpr function can be called at compile time successfully, it will also be guaranteed not to have UB at runtime, in general.

I was pointing out that this is only true for the cases you actually test, not the general case.

Even then, it's not fully true, as a function may have different behavior at runtime as opposed to compile time (e.g. because of multi-threading), and so it may display UB even when called with the same arguments that didn't display UB at compile-time.

Overall, this static_assert trick is just a nice way to make sure your tests don't accidentally pass while still invoking UB, to protect from false negatives.

Aha, I think I see. Upon reflection, I do remember that some people seem to think that UB is a property of the code, not the execution; that a piece of code either "contains UB" or does not. I suppose it makes sense then that some people may think that code which works under constexpr can't "contain UB" and get the wrong idea.
Try forcing the call to happen at compile-time.

constexpr requires that the function be callable at compile-time, not that it is so.

You can't call an expression whose value is IO-dependent in a compile-time context, obviously.

The tweet seems to imply that if you can call your functions at compile time, they will not present UB at runtime either. I am trying to point out that that is not the case at all.

That seems unrelated to the sub-thread in question.
The example program is calling foo(y), where the value of y is read from standard input. You suggested to evaluate that expression at compile time, which is not possible. How is this unrelated to the thread?
By forcing the call to happen at compile-time, he would get an error.

The input being potentially known at compile-time is not sufficient to make a constexpr function be called at compile-time.

Yes, but that error would simply complain that a variable that doesn't have a compile time known value is been used in a compile time context.

Conversely, the origin of the thread implies that if a function has been successfully called with some argument from a static_assert, it will not have UB at runtime even if called with some other arguments. This subthread was showing that this is not the case, and that you can't test all uses of a function using static_assert to guarantee that it will not exhibit UB.

In case it's not clear, this piece of code will also fail to compile, even though it exhibits no UB:

  constexpr int foo(int y) {
    return y;
  } 
  int y;
  std::cin>>y;
  static_assert(foo(y));
https://godbolt.org/z/xvhP8nq7z