Nuno,
One of your recent emails got me thinking about inlining.
I say this function is always well defined,
And it always executes statement S
F(a)
{
If (a == a) S;
}
And that if this function is inlined it must still be well defined,
And still always execute statement S
But if I read your example correctly you feel that the result
of inlining is undefined behavior because “if (undef == undef)”
and “if (poison == poison)” is undefined behavior ?
I say that if the compiler makes it so that the programmer cannot
correctly reason about how their program executes then there is
something wrong with the compiler.
My own opinion about this is that it is yet another example of why
"Since each use of ‘undef’ can yield a different result…”
is such a bad definition, and should never have been accepted into
the IR in the first place.
IIUC, both “undef” and “poison” share this undesirable definition
for which “freeze” is proposed as a fix, but if I understand your
logic correctly there is no way to fix this example with “freeze” ?
IMHO "freeze” is a bandaid over a bad definition, that doesn’t
seem to solve the inlining problem, and we should fix the definition
rather than add a bandaid.
Hi Peter, I don't see what you're driving at here. You can perhaps move
the discussion forward with a complete, compilable example.
John
I don't KNOW for sure, but I think I understand, see below:
Nuno,
One of your recent emails got me thinking about inlining.
I say this function is always well defined,
And it always executes statement S
F(a)
{
If (a == a) S;
}
I think the problem can be seen as:
void F(int a)
{
if (a == a) do_stuff();
}
....
main()
{
int x;
F(x);
}
If the compiler doesn't inline F, it will definitely call F, where the
compiler doesn't KNOW that x is undef, and as a result, do_stuff is
guaranteed to execute. If F is inlned, x is known as undef, so the compiler
decides that the comparison is false (despite x always has to be equal to
itself, no matter whether it's value is undef or not), and thus do_stuff
wlll not be called.
Of course, it would be easy to fix this by initializing x, but with some
more complex code, it may not be so easy to follow what is going on and
what the effects will be.
I don't have a good answer as to what to do - I can sort of see both sides
on this one.
I understand that is the "letter of the law". However, I can see the
argument for something that behaves in a predictable way, whether for
example F is defined in a header file or in a separate translation unit -
and I believe the example here is one where that would make a difference -
even if the compller is perfectly fine to produce something that plays the
theme tune to Mony Python's Flying Circus or prints 42 on the screen,
instead of whatever "do_stuff" does.
I understand that is the "letter of the law". However, I can see the
argument for something that behaves in a predictable way, whether for
example F is defined in a header file or in a separate translation unit
- and I believe the example here is one where that would make a
difference - even if the compller is perfectly fine to produce something
that plays the theme tune to Mony Python's Flying Circus or prints 42 on
the screen, instead of whatever "do_stuff" does.
This ship has sailed.
If you want predictability for UB you'll need to get it through a sanitizer, a non-optimizing compiler, a special-purpose command-line flag that disables a class of UB-exploiting optimizations, etc.