Sitesh
Sitesh

Reputation: 1878

Runtime errors with constexpr

Consider the below code snippets

constexpr int divide( int x, int y)
{
    return (x/y);
}

constexpr int div_by_zero( int x)
{
    return (x/0);
}

Case 1 :

int x = divide(10,0);

This compiles successfully (with both gcc and clang) but produces the below runtime error.

Floating point exception (core dumped)

Case 2 :

int y = div_by_zero(10);

This gives a Compiler error,

(g++ -std=c++17) division by zero is not a constant expression

NOTE : clang does not throw error even in this case

And also Compiler warnings:

(clang++ -std=c++17), division by zero is undefined [-Wdivision-by-zero]

(g++ -std=c++17), division by zero [-Wdiv-by-zero]

For Case 1, why the compiler does not complain even when the value for second argument is known(i.e. zero) during the compile time ?

Example here divide(10,2); generates below assembly code

  mov rbp, rsp
  sub rsp, 16
  mov DWORD PTR [rbp-4], 5

divide(10,0); generates below assembly code

  mov esi, 0
  mov edi, 10
  call divide(int, int)

There is call to divide() when the input is zero. The same is evaluated at compile time when non-zero values are the input to the function. If a compiler is able to find out and call the method instead of evaluating, why an error can't be thrown ?

Upvotes: 2

Views: 241

Answers (2)

Barry
Barry

Reputation: 304122

The fact that divide(10, 0) doesn't warn is a Quality of Implementation (QoI) issue. You could file a bug with gcc about it. But note that such arbitrary constant tracking isn't always feasible.

But the fact that div_by_zero(10) doesn't compile is slightly different. From [dcl.constexpr]/5:

For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression, or, for a constructor, a constant initializer for some object ([basic.start.static]), the program is ill-formed, no diagnostic required.

One of the restrictions of what constitutes a core constant express is that it cannot invoke undefined behavior, which includes division by zero.

So for divide(), there are arguments that you can pass that would make the call a valid constant expression. But for div_by_zero(), there does not exist any argument you can provide to make it a constant expression - which makes the program ill-formed.

Upvotes: 3

Ivan Sanz Carasa
Ivan Sanz Carasa

Reputation: 1387

Your functions are constexpr, this means that they will be evaluated as constexpr (compile-time) when the context allows it. In your usage, the context isn't constexpr so it defers the calculation to runtime. https://godbolt.org/g/Jo5GyL

int x = div(10, 0); // x isn't a constexpr var, calculation in runtime
constexpr int y = div(10, 0); // y is constexpr, calculation in compile-time + error

On your second example, the division part is well-defined: x / 0. That's why the compiler knows that this will fail and reports the error even if the function isn't invoked at compile-time (again, lack of constexpr in var y).

Upvotes: -1

Related Questions