3

I have an Assert function that I use to evaluate assertion:

  • if the precondition fails at runtime, this function will output an error message and it will terminate the program.

  • if the precondition fails inside a constant expression, it will cause a compile time error.

I would like that this function also generates a compile time error when the assertion fails in constant evaluated expression:

const int a = (Assert(false),0); //generate a runtime error 
                                 //=> I would like it generates a compile time error

I thought about using std::is_constant_evaluated: compiler-explorer

#include <type_traits>

using namespace std;

void runtime_error();

constexpr void compile_time_error(){} //should generates a compile time error

constexpr void Assert(bool value){
   if (value) return;
   if (is_constant_evaluated())
     compile_time_error();
   else
     runtime_error();
   }

void func(){
    const int a = (Assert(false),0);
    }

I only use GCC, I have look for a builtin function that would cause a compile time error and that would be a constexpr but did not find one.

Is there any trick to get a compile time error in expression that could be constant evaluated?

Oliv
  • 17,610
  • 1
  • 29
  • 72
  • `static_assert` is evaluated at compile time. The expression it checks therefore must be `constexpr`, not just `const`. And that is the problem: Compilation of your function `compile_time_error` function would always fail. – Rene Jan 06 '20 at 11:22
  • Just use `runtime_error()`. It will cause an error if it is evaluated at compile time. – cpplearner Jan 06 '20 at 11:27

1 Answers1

5

You can call a function that is nowhere defined to cause a compile time error. Or, since you are using gcc anyway, you can call a attribute error function from inside the constant part to cause a compile time error during compilation of this unit. To make it work, you have to compile with optimizations enabled.

I see that with std::is_constant_expression it does not work in gcc 9.2, but I managed it to work with __builtin_constant_p.

#include <type_traits>

constexpr void Assert(bool value) {
   if (__builtin_constant_p(value)) {
        if (!value) {
            extern __attribute__(( __error__ ( "error" ) ))
            void compile_time_error(void);
            compile_time_error();
        }
    } else {
        if (!value) {
            void runtime_error();
            runtime_error();
        }
   }
}

void func(int b) {
    const int a = (Assert(false), 0);
    Assert(b == 0);
}

I have once written a library in C I called curb that would do something like this.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • GCC still respects the constant-initialization contract and does regular initialization instead https://godbolt.org/z/afrvEM – StoryTeller - Unslander Monica Jan 06 '20 at 11:35
  • Thank you! Actualy it only work with `__builtin_constant_p`, not with `is_constant_evaluate()`. – Oliv Jan 06 '20 at 11:45
  • 1
    Does this guarantee an error by the standard, or is it just common behaviour? – M.M Jan 06 '20 at 11:59
  • There is nothing in the standard about `__builtin_constant_p`. It is a private gcc call. Hence, it is neither guaranteed to work nor common behavior. But it SHOULD work for current versions of gcc. – Marshall Clow Jan 06 '20 at 16:57
  • Note that this answer doesn’t depend on the `Assert(false)` being (part of) a *constant expression*; it triggers if the argument is *known* to the compiler (possibly because of optimization). – Davis Herring Jan 08 '20 at 04:12