Is a C implementation required to ignore undefined behaviors occurring during the evaluation of void expressions as if the evaluation itself never took place?
Considering C11, 6.3.2.2 §1:
If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)
This is related to the common idiom used to prevent compilers from warning about unused variables:
void f() {
int a;
(void)a;
}
But what if we have undefined behavior, such as:
void f() {
int a;
(void)(1/0);
}
Can I safely claim that this program contains no undefined behavior? The standard says that "its value or designator is discarded", but the "expression (...) is evaluated (...)", so the evaluation does seem to take place.
GCC/Clang do report the undefined behavior, since it is obvious in this case, but in a more subtle example they don't:
int main() {
int a = 1;
int b = 0;
(void)(a/b);
return 0;
}
Even with -O0
, neither GCC nor Clang evaluate 1/0
. But that also happens even without the cast to void, so it's not representative.
Pushing the argument to its extreme, wouldn't the simple evaluation of (void)a
in my first example (where a
is uninitialized) systematically trigger undefined behavior?
ISO C11 6.3.2.1 §2 does mention that:
If the lvalue designates an object of automatic storage duration that could have been declared with the register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined.
However, in the Annex J.2 Undefined behavior, the phrasing is slightly different:
The behavior is undefined in the following circumstances:
(...)
An lvalue designating an object of automatic storage duration that could have been declared with the register storage class is used in a context that requires the value of the designated object, but the object is uninitialized. (6.3.2.1).
This annex does lead to the interpretation that a void
expression containing undefined behavior during its evaluation is not actually evaluated, but since it's just an annex, I'm not sure of its argumentative weight.
(void)a
is in grey area. 6.3.2.2: "If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)" – Landslidehttps://www.godbolt.org/z/4tHKGg
: actually the expression is evaluated partially, that is thef
function is called three times, but the division and the addition in the expression are not evaluated (because the result is ignored). But IMO a compiler could generate the code for the division and the addition and then ignore the result. – Revocation