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

            Bug ID: 71113
           Summary: Adding "const" to value in constexpr constructor
                    places const object in .bss instead of .rodata
           Product: gcc
           Version: 6.1.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: freddie_chopin at op dot pl
  Target Milestone: ---

Take a look at following test case:

-- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 --

class X
{
public:

        constexpr X(void* pointer) :
                pointer_{pointer}
        {

        }

private:

        void* pointer_;
};

#define PERIPHERAL1     (void*)0x20000000
const X xxx {PERIPHERAL1};

int main()
{

}

-- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 --

Execute test:

-- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 --

$ g++ test.cpp && objdump -x --syms --demangle a.out | grep xxx
0000000000400608 l     O .rodata        0000000000000008              xxx

-- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 --

Everything's fine. Now just add one trivial change, which does _NOT_ change any
logic (at least in my opinion (; ). Replace:

        constexpr X(void* pointer) :

with

        constexpr X(void* const pointer) :

And the object is placed in .bss, not in .rodata...

-- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 --

$ g++ test.cpp && objdump -x --syms --demangle a.out | grep xxx
0000000000600a58 l     O .bss   0000000000000008              xxx

-- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 --

There's no problem if an address of "real" object is used, so for example
something like this works fine in both cases:

-- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 --

int something;
const X xxx {&something};

-- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 --

The use case may seem a bit strange, but the macro definition like the one used
in the example is used commonly in hardware headers for microcontrollers. They
usually look like this:

-- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 --

#define PERIPH_BASE           ((uint32_t)0x40000000U)
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x00010000U)
#define USART1_BASE           (APB2PERIPH_BASE + 0x1000U)
#define USART1              ((USART_TypeDef *) USART1_BASE)

-- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 --

(USART_TypeDef is a typedef of an anonymous struct with layout of peripheral
registers)

The behaviour was noticed in GCC compiled for "arm-none-eabi-", version 5.3.1,
but the same thing happens in a desktop version 6.1.1 on Arch Linux.

Reply via email to