Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Static inline variable and global are initialized in incorrect order with optimization on #116950

Open
semushin-s opened this issue Nov 20, 2024 · 2 comments

Comments

@semushin-s
Copy link

Please take a look at the following example:

struct A {
	A() {
        a = 1;
    }

    int a;
};

struct B {
	B() : _a(_ca) {}

	A _a;
	static inline A _ca;
};

B b;

int main() {
	return b._a.a;
}

Currently it returns 0 with -O2 using clang:
https://gcc.godbolt.org/z/66hGqoaj8
and returns 1 with -O0. Compiled by all the other compilers, it results in 1 as well.

It seems initialization of static inline A _ca should be done earlier than initialization of B.
According to [basic.start.dynamic]:
if V has partially-ordered initialization, W does not have unordered initialization, and for every definition E of W there exists a definition D of V such that D is appearance-ordered before E ... V is sequenced before the initialization of W;

Let's say static inline A _ca is definition of V, B b is definition of W, seems by appearance order _ca should have been initialized before b, however with optimization a=1 initialization fails to happen before initializing B b apparently. Please correct me if my interpretation of the standard is wrong in this case.

@semushin-s
Copy link
Author

Another interesting aspect of this issue, coming from how it was discovered originally. Initialization order may be affected by adding irrelevant global constants to original example.
Basically it comes to the following:

  • Adding const std::string global constant on top makes initialization work expectedly in clang trunk but only with C++17. Link to godbolt
  • On clang 17, it seems to behave expectedly with both C++17 and 20 after the same addition. Link to godbolt

Might not be that relevant since it might be just optimization noise, but makes it more surprising when encountering this in the wild.

@etl
Copy link

etl commented Dec 27, 2024

Adding any other struct member or increasing data size adds runtime initialization of _ca and returned value is correct:

struct A {
	A() {
        a = 1;
    }

    int a;
    int b;  // fixes issues
};

struct B {
	B() : _a(_ca) {}

	A _a;
	static inline A _ca;
};

B b;

int main() {
	return b._a.a;
}```

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

3 participants