The following code that puts two static variables into their own section won't compile because of a section type conflict. class C { public: void m() { static const int TWO __attribute__((section(".consts"))) = 2; } }; static void c() { static const int ONE __attribute__((section(".consts"))) = 1; } int main (int argc, char **argv) { C inst = C(); inst.m(); c(); return 0; } $ g++ section.cxx section.cxx:12: error: ONE causes a section type conflict The section should have the same type in both definitions, but apparently doesn't.
Actually, they have to have two different section types. c::m()::TWO has to be in the comdat section for C::m(). While c()::ONE does not and can be in a normal section.
(In reply to comment #1) > Actually, they have to have two different section types. > > c::m()::TWO has to be in the comdat section for C::m(). > While c()::ONE does not and can be in a normal section. INVALID? How is the user supposed to know (or care) about comdat? All they want is make sure the constants get put in the same section. So how can one specify that behavior for both ONE and TWO?
See comment #2.
The compiler is being internally inconsistent here. It somtimes decides that __attribute__((section ("name"))) means a "name" section in a COMDAT group, and sometimes decides that it means just a plain "name" section. If it's going to have that behavior implicitly, then it should not call this a conflict. Instead, it should implicitly recognize that the particular COMDAT version of "name" is a different animal than the non-COMDAT "name". In fact, it has an arguably more severe version of this bug too: class C { public: void m() { static int TWO __attribute__((section(".consts"))) = 2; } }; class D { public: void m() { static int THREE __attribute__((section(".consts"))) = 2; } }; int main (int argc, char **argv) { C inst = C(); inst.m(); D inst2 = D(); inst2.m(); return 0; } For that, it happily puts TWO and THREE initializers both in the COMDAT group for C::m()::TWO, which is quite clearly wrong. The left hand uses multiple different sections of the same name, but the right hand thinks that any section matching the simple name it's looking for is the same thing regardless of whether or not its a distinct COMDAT variant.
I see no error for the test case in comment #0 with the top of trunk (GCC 7.0) so I'm resolving this report as fixed. Please reopen it if the problem persists with different symptoms.
The following code reproduces this, or a very similar issue: #define STORE(SECTION, STRING) \ __attribute__((section(SECTION), used)) \ static constexpr const char* s[] = { STRING } void f() { STORE(".custom", "normal_foobar"); } inline void g() { STORE(".custom", "inline_foobar"); } template <typename = void> void h() { STORE(".custom", "template_foobar"); } int main() { f(); g(); h(); return 0; } $ g++ -std=c++11 section.cpp section.cpp: error: 's' causes a section type conflict with 's' GCC 4.8, 5.2, 7.2, and trunk are affected (x86-64, checked on godbolt). Depending on the compiler version, either the normal and the inline, or the normal and the function template clashes. I suppose because of how comdat is handled, they might have slightly different needs, but it would be really nice to make it easier for the user. (Clang compiles it fine)
Thanks for the test case. I can confirm the error on trunk (GCC 8.0). Reopening.
Issue persists in gcc 10.2, test program from comment #6 still errors out. We're hitting this bug in production/real-world code [ https://github.com/FRRouting/frr/pull/6766 ]. What we're doing is very similar to SystemTap's trace points, I believe those might be affected as well. clang++ works fine meanwhile.
My team is also impacted by this issue (also with tracing code, as it turns out). FWIW there's a great writeup explaining the issue on Stack Overflow: https://stackoverflow.com/questions/35091862/inline-static-data-causes-a-section-type-conflict In this writeup, the author suggests that perhaps -fno-gnu-unique should additionally cause GCC to _not_ use section grouping for the associated symbol; in this case GCC would simply emit a weak symbol without grouping, which I believe would match the (admittedly less robust) behavior of Clang.
I really doubt there is a good solution for this because of what c++ calls vague linkage. Clang's solution is broken too.