The below test case fails to link with clang. gcc48 does work. ----- extern void dead(void); void test(int x) { if (x || 1) return; dead(); } int main() { test(0); return 0; } ----- When I change the if (x||1) to if(1||x) the compile/link succeeds. Here the output of the failing test: [tcx58:~] andreast% clang -o dead dead.c /tmp/dead-hllbPY.o: In function `test': dead.c:(.text+0x2d): undefined reference to `dead' clang: error: linker command failed with exit code 1 (use -v to see invocation) The original code was discovered in qemu-trunk, the workaround is to change the if condition. The credit for the test case and the workaround goes to Paolo Bonzini. I have tested this on FreeBSD -CURRENT: [tcx58:~] andreast% clang -v FreeBSD clang version 3.3 (tags/RELEASE_33/final 183502) 20130610 Target: x86_64-unknown-freebsd11.0 Thread model: posix
This is not a bug. Try building with optimisation enabled.
Hm, I can confirm that O2 (if that is correct) compiles and links correctly. So that would mean I have to write code different when I want to debug?
(In reply to comment #2) > Hm, I can confirm that O2 (if that is correct) compiles and links correctly. > So that would mean I have to write code different when I want to debug? The code is incorrect either way, but you're much more likely to get away with writing this broken code if you use -O2, because the bogus reference to the undefined function is much more likely to be optimized away that way.
I'm afraid if clang wants to be compatible with GCC this has to be fixed. Having some kind of -O0 dead-code elimination is definitely a feature of GCC (http://gcc.gnu.org/ml/gcc-patches/2003-03/msg02443.html), and that first implementation already handled "||" and "&&" just fine even though it didn't handle this testcase due to the "return" in the clause of the "if" statement. This testcase fails with clang, and should work with GCC 3.4: extern void dead(void); void test(int x) { if (x || 1) ; else dead(); } int main() { test(0); return 0; }
(In reply to comment #4) > Having some kind of -O0 dead-code elimination is definitely a feature of GCC > (http://gcc.gnu.org/ml/gcc-patches/2003-03/msg02443.html) That post seems to imply that this is an optimization directed towards improving the generated -O0 code quality, not a language extension designed to allow invalid code.
Yes, it's invalid code but it doesn't mean this is not an issue in terms of quality of implementation. Optimizing away code after a "break", even at -O0, seems to me like a deliberate choice and looks harder than handling "if (X || 1)" the same as "if (1 || X)". This is why I suggested to Andreas that he reported this as a clang bug. There's a reason why trivially-dead code elimination is good to have at -O0. Wrapping dead code with "if"s instead of #ifdef avoids syntax errors that sneak into those parts of the code that are #ifdef'ed out. And it's a reasonable assumption that this (useful) trick works in both debug and release builds. Since clang/LLVM does not provide a "debuggability" option like GCC's -Og, and -O1 is only documented as "somewhere between -O0 and -O2", -O0 is the only alternative for debug builds. In contrast, GCC's documentation mentions explicitly that -O1 does not affect debuggability in addition to being faster than -O2; in addition -Og activates _all_ -O2 optimizations that do not affect debuggability, with no particular regard to compilation speed.