https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102876

--- Comment #12 from Mathias Stearn <redbeard0531 at gmail dot com> ---
(In reply to Jakub Jelinek from comment #10)
> So we'd just punt at optimizing that, we don't know if b is read or written
> by foo (and, note, it doesn't have to be just the case of explicitly being
> passed address of some var, it can get the address through other means).
> On the other side, we can't optimize b to b: .long 2, because bar can use
> the variable and/or modify it, so by using 2 as static initializer bar would
> be miscompiled.

I'm pretty sure that that is explicitly allowed by
https://eel.is/c++draft/basic.start.static#3, so it should *not* be considered
a miscompilation. The example only shows reading from another static-duration
variable's initializer, but I believe writing would also be covered.

I took a look at how other compilers handle this, and it is somewhat
interesting: https://godbolt.org/z/9YvcbEeax

int foo(int&);
inline int bar() { return 7; }
extern int b;
int z = bar();
int a = foo(b); // comment this out and watch clang change...
int b = bar();
int c = bar();

GCC: always does dynamic init for everything.
MSVC: always does static init for z, b, and c. always dynamic init for a.
Clang: it seems like if it does any dynamic init in the TU, it doesn't promote
any dynamic init to static. So with that code all four variables are
dynamicially initialized, but if you comment out a, the remaining 3 become
static. If you add an unrelated variable that requires dynamic init, those 3
become dynamically initialized again.

I don't understand why clang does what it does. I don't think it is required to
do that by the standard, and it clearly seems suboptimal. So I would rather GCC
behave like MSVC in this case than like clang.

Also note what happens if we provide a definition for foo like `inline int
foo(int& x) { return x += 6; }`: https://godbolt.org/z/sWd6chsnP. Now both MSVC
and Clang will static initialize z, b, and c to 7 and *static* initialize a to
6. GCC gets the same result dynamically, but for some reason tries to load b
prior to adding 6, even though it has to be 0 (barring a UB write to b from
another TU).

Reply via email to