The assertion in the following program should never fail because variables with automatic storage duration in a function should be created for each recursive invocation, and such distinct objects' address should not compare equal. #include <assert.h> #include <stdio.h> int f(const int* p) { const int c[] = {12345,56789}; assert(p != c); if (p == 0) { return f(c); } puts("Done."); return 0; } int main() { f(0); } Clang 3.3 seems violating the rule and causes an assertion failure. http://melpon.org/wandbox/permlink/tYmnEVjMNP33nYHr > prog.exe: prog.c:6: int f(const int *): Assertion `p != c' failed. I'm referring WG14 N1570. http://www.open-std.org/jtc1/sc22/wg14/www/standards.html From 6.2.4 p6: > For such an object that does not have a variable length array type, its > lifetime extends from entry into the block with which it is associated > until execution of that block ends in any way. (Entering an enclosed > block or calling a function suspends, but does not end, execution of the > current block.) If the block is entered recursively, a new instance of > the object is created each time. 6.5.9 p6 > Two pointers compare equal if and only if both are null pointers, both > are pointers to the same object ... If the variable is not an array, there seems no problem. http://melpon.org/wandbox/permlink/uYeR8GbRvuQN3CMC
Created attachment 11891 [details] Bitcode of the compiled program Still happens with clang r199081. Going by the bitcode (attached) clang transforms the const int c[] = {12345,56789}; into static const int c[] = {12345,56789}; as its contents is constant at compile-time and thus doesn't need to be created on the stack each time <f> is called (except of course when its address is compared).
*** Bug 18557 has been marked as a duplicate of this bug. ***
This is a (non-conforming) optimization, and can be disabled with -fno-merge-all-constants. I'm not sure why our default mode is non-conforming; possibly this optimization is very important on some code at -O0.
*** Bug 19070 has been marked as a duplicate of this bug. ***
Any update on this? The workaround isn't difficult, but I would think that Clang by default would try to be standards conforming, and any non-standard behavior would need to be explicitly opted into by the user. Does Clang enable any other non-standards-conforming optimizations by default?
This is the only case I can think of (off the top of my head) where clang deliberately does not conform to the standard by default, and has a flag to make it conform. There are a few other places where we deliberately don't conform because we think the standard is wrong (and generally we try to get the standard fixed in those cases).
As long as we emit a code pattern that LLVM can easily turn back into the static equivalent, I think being standards-compliant
(Sigh.) As long as we emit a code pattern that LLVM can easily turn back into the static equivalent, I think being standards-compliant by default is the right thing to do. I'm pretty sure that Chris wrote this particular code; CC'ing him for his input.
I'm not morally invested in this optimization, but I have to ask: why do you guys care about this? Is it actually causing a problem in practice? Is it causing a failure on some standards test suite, or something else?
No problem in practice, at least for me. I've learned that the lack of the static specifier causes unwanted stack usage and repeated initialization in practice, and that are mandated by the standard over a few decades. Then I used to be, and encourage others to be, careful not to forget the static specifier. I noticed this issue as going against my (and probably some others') observance. Additionally, I can think of a portability problem that might be caused by this behavior: A conforming program might rely on the address uniqueness of the constants without static specifier. If such a program was ported to clang, it would break silently.
*** Bug 25955 has been marked as a duplicate of this bug. ***
*** Bug 27443 has been marked as a duplicate of this bug. ***
(In reply to Chris Lattner from comment #9) > I'm not morally invested in this optimization, but I have to ask: why do you > guys care about this? Is it actually causing a problem in practice? Is it > causing a failure on some standards test suite, or something else? This optimization hasn’t caused any functional problems in practice, but we have seen more of a human/social problem. Observing Clang perform this optimization has caused us to assume that, at function scope, a “static const” array (with true constant-expression initialization) is no different than a plain “const” one, and to prefer the less noisy “const” form, and even to standardize on it. That source code compiles to what we intended when fed to Clang, but it’s not so good when you bring it to other compilers, which produce less optimal code without “static” semantics unless you’re explicit.
Ok, well, this is an incredibly old thread. In the modern world, the optimization should only be applied to unnamed_addr globals.
This was recently cited on LKML: https://lkml.org/lkml/2018/3/20/872
I think there's consensus that we should not be doing this by default, and we just need someone to write a patch to fix it. Doing it for unnamed_addr constants does not require user intervention; it's an as-if optimization.
Patch at https://reviews.llvm.org/D45289
Submitted as https://reviews.llvm.org/rL329300