Question about ExprConstant optimization of IR stage

hi,
I compile a case (test.c) to get IR file (test.ll) using clang as follows:
“clang -emit-llvm -S -O2 test.c -o test.ll”
My clang source code version is release 3.3 and debugging build.
//test.c
int foo(int j) {
return ++j > 0;
}
int main() {
if (foo(((~0U)>>1)))
abort();
exit(0)
}
//end test.c

Here are the generated IR file:
//test.ll
; Function Attrs: noreturn nounwind uwtable
define i32 @main #1 {
if.then:
tail call void @abort() #3
unreachable
}
//end test.ll

As we can see from test.ll, foo function is optimized out by clang.
And then call abort function directly.

However, the real is that this test never executes abort function.
So, I debug source code of clang.
In the 3167 line of ExprConstant.cpp(tools/clang/lib/AST/ExprConstant.cpp),
these codes are
3166: // Don’t call function pointers which have been cast to some other type.
3167: if (!Info.Ctx.hasSameType(CalleeType->getPointeeType(), FD->getType()))
3168: return Error(E);
It returns Error(E) . Then, the expression “foo(((~0U)>>1))” is optimized out in the later stage.
Here FD is foo’s function pointer, so I think it should not return Error.
Maybe it is bug, could someone help me with that?

Thanks a million in advance.
–Haishan

Hi Haishan,

  int foo(int j) {
    return ++j > 0;
  }
  int main() {
    if (foo(((~0U)>>1)))
      abort();
    exit(0)
  }

This test contains undefined behaviour, and you can never rely on the
compiler doing anything predictable with that. Specifically, the
result of casting (~0U) >> 1 to an int is almost certainly INT_MAX and
when foo increments it integer overflow occurs, which is undefined.

Cheers.

Tim.

Hi Tim,
Firstly, thanks for your reply.
I agree on your idea about integer overflow in this test.
But, in fact, the content of this test is the same to gcc\testsuite\gcc.c-torture\execute\920612-1.c.
gcc can handle it correctly.
Moreover, when I compile this test using clang with optlevel O0 instead of O2.
Its execution result is the same to gcc.
That to say, for this test, clang with optlevel O2 execution result is different from O0.
Is it reasonable?

Thanks a lot.
-Haishan

Hi Haishan

But, in fact, the content of this test is the same to gcc\testsuite\gcc.c-torture\execute\920612-1.c.
gcc can handle it correctly.

It looks like[1] GCC handles it by compiling the test with the flag
"-fwrapv" which tells the compiler to override the normal language
rules and treat integer overflow as defined and consistent with a
2s-complement representation.

Clang also supports this option, though personally I'd strongly
discourage it except for unmaintained and unmaintainable legacy code.

That to say, for this test, clang with optlevel O2 execution result is
different from O0. Is it reasonable?

Yes. It's one of the perils of undefined behaviour.

Cheers.

Tim.

[1] https://github.com/mirrors/gcc/blob/master/gcc/testsuite/gcc.c-torture/execute/920612-1.x