Reputation: 1878
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
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
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