[Bug lto/105876] New: use of -flto with g++ changes global extern const std::string initialization in unexpected manner

2022-06-07 Thread kevin.b.hendricks at icloud dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105876

Bug ID: 105876
   Summary: use of -flto with g++ changes global extern const
std::string initialization in unexpected manner
   Product: gcc
   Version: 12.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: lto
  Assignee: unassigned at gcc dot gnu.org
  Reporter: kevin.b.hendricks at icloud dot com
CC: marxin at gcc dot gnu.org
  Target Milestone: ---

Created attachment 53101
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=53101&action=edit
text copy of the above for extracting source code

Use of -flto with g++ causes extern const std::string variable to be
initialized after a static const class variable.

This behaviour is not present when -flto is not used.  This same simple test
case works with and without -flto with clang++.

$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/12.1.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure
--enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-bootstrap
--prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man
--infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/
--with-linker-hash-style=gnu --with-system-zlib --enable-__cxa_atexit
--enable-cet=auto --enable-checking=release --enable-clocale=gnu
--enable-default-pie --enable-default-ssp --enable-gnu-indirect-function
--enable-gnu-unique-object --enable-linker-build-id --enable-lto
--enable-multilib --enable-plugin --enable-shared --enable-threads=posix
--disable-libssp --disable-libstdcxx-pch --disable-werror
--with-build-config=bootstrap-lto --enable-link-serialization=1
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 12.1.0 (GCC) 

uname -a
Linux kevin-virtualbox 5.15.41-1-MANJARO #1 SMP PREEMPT Wed May 18 09:20:01 UTC
2022 x86_64 GNU/Linux


Simple Test Case Sources
-

--- sg_constants.h ---
  #include 
  extern const std::string MAIN_EXTERN_CONST_STRING;

--- sg_test.h ---
  class sg_test
  {
  public:
sg_test();
  };


--- main.cpp ---
  #include 
  #include 

  #include "sg_constants.h"
  #include "sg_test.h"

  const std::string MAIN_EXTERN_CONST_STRING= "a_literal_string_value";

  int main(int argc, char *argv[])
  {
(void) argc; (void) argv;
std::cout << "In main MAIN_EXTERN_CONST_STRING is: " << "'" <<
MAIN_EXTERN_CONST_STRING << "'" << std::endl;
sg_test * psg = new sg_test();
(void) psg;
return 0;
  }


--- sg_test.cpp ---
  #include 
  #include "sg_constants.h"
  #include "sg_test.h"

  static const std::string TEST_STATIC_CONST_STRING = MAIN_EXTERN_CONST_STRING;

  sg_test::sg_test()
  {
std::cout << "In sg_test object TEST_STATIC_CONST_STRING is: " << "'" <<
TEST_STATIC_CONST_STRING << "'" << std::endl;
std::cout << "In sg_test object MAIN_EXTERN_CONST_STRING is: " << "'" <<
MAIN_EXTERN_CONST_STRING << "'" << std::endl;
  }



$ cat buildme.sh
g++ -I. -g -O2 -Wall -Wextra -c sg_test.cpp
g++ -I. -O2 -Wall -Wextra -c main.cpp
g++ -o no_lto_test *.o
rm -f *.o

g++ -I. -g -O2 -flto=auto -Wall -Wextra -c sg_test.cpp
g++ -I. -g -O2 -flto=auto -Wall -Wextra -c main.cpp
g++ -flto=auto -o lto_test *.o

echo "Without lto"
./no_lto_test
echo " "
echo "With lto"
./lto_test


$ ./buildme.sh

Without lto
In main MAIN_EXTERN_CONST_STRING is: 'a_literal_string_value'
In sg_test object TEST_STATIC_CONST_STRING is: 'a_literal_string_value'
In sg_test object MAIN_EXTERN_CONST_STRING is: 'a_literal_string_value'

With lto
In main MAIN_EXTERN_CONST_STRING is: 'a_literal_string_value'
In sg_test object TEST_STATIC_CONST_STRING is: ''
In sg_test object MAIN_EXTERN_CONST_STRING is: 'a_literal_string_value'

[Bug lto/105876] use of -flto with g++ changes global extern const std::string initialization in unexpected manner

2022-06-07 Thread kevin.b.hendricks at icloud dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105876

--- Comment #2 from Kevin Hendricks  ---
Created attachment 53102
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=53102&action=edit
zip archive with simple test case and build script

To make testing easier I have attached a small zip with the source files and
build shell script.

[Bug lto/105876] use of -flto with g++ changes global extern const std::string initialization in unexpected manner

2022-06-07 Thread kevin.b.hendricks at icloud dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105876

--- Comment #3 from Kevin Hendricks  ---
I thought the C++ spec said that static initialization is done in two phases. 
global (extern cost) variable are always initialized in the order they are
declared first and local (dynamic) static initialization is always done second
(and order across compilation units is undefined as your say).

By definition isn't a global variable available in all translation units.

When compiled *without* -flto, the compiler properly recognizes the extern
const std::string variable as global while the static initializer in the
sg_test class is considered local (all based on nm).  In that case
initialization order is global then local.

But when compiled to -flto somehow the "extern" nature of the declaration is
lost, and the variable becomes just another local static initializer and
therefore the issue of a race (which is initialized first) happens.

That should not be happening between a global (extern cost) and a local
(sg_test class static const) object.

[Bug lto/105876] use of -flto with g++ changes global extern const std::string initialization in unexpected manner

2022-06-07 Thread kevin.b.hendricks at icloud dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105876

--- Comment #5 from Kevin Hendricks  ---
It was declared in sg_constants.h as:

extern const std::string MAIN_EXTERN_CONST_STRING;

But why was its global nature lost:

Based on nm output:

./no_lto_test:1210 t
_GLOBAL__sub_I__Z24MAIN_EXTERN_CONST_STRINGB5cxx11
./no_lto_test:41e0 B _Z24MAIN_EXTERN_CONST_STRINGB5cxx11
./no_lto_test:4220 b _ZL24TEST_STATIC_CONST_STRING

---

./lto_test:4100 b _Z24MAIN_EXTERN_CONST_STRINGB5cxx11
./lto_test:40e0 b _ZL24TEST_STATIC_CONST_STRING

and there is no global initialization routine anymore at all


So you are saying this is because a std::string constructor can not be
considered const even though it is a object that can be fully constructed and
allocated in pieces as a fixed structure datatype.

So my solution is everywhere we use extern const std::string, I either have to
change it to an untyped define/macro and give up type safety or change it to 
be a:

 extern const char * 

just so that it gets initialized as a proper global variable?

That really makes std::string a second class citizen.

[Bug lto/105876] use of -flto with g++ changes global extern const std::string initialization in unexpected manner

2022-06-07 Thread kevin.b.hendricks at icloud dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105876

--- Comment #7 from Kevin Hendricks  ---
It kind of flies in the face of how g++ without -flto worked over the long term
(and clang++ and even the microsoft compiler) but ...


Thank you for taking the time to explain things.