Lets compile the following top-level declaration
const int& ri = 5;
with clang++
. With -std=c++14
and below it places the temporary object (and the pointer representing the reference) into the .rodata
section:
.type _ZGR2ri_,@object # @_ZGR2ri_
.section .rodata,"a",@progbits
.p2align 2
_ZGR2ri_:
.long 5 # 0x5
.size _ZGR2ri_, 4
.type ri,@object # @ri
.globl ri
.p2align 3
ri:
.quad _ZGR2ri_
.size ri, 8
But if we change the standard version to -std=c++17
(or above), the object will be placed into the .data
section (the pointer is still in the .rodata
, though):
.type _ZGR2ri_,@object # @_ZGR2ri_
.data
.p2align 2
_ZGR2ri_:
.long 5 # 0x5
.size _ZGR2ri_, 4
.type ri,@object # @ri
.section .rodata,"a",@progbits
.globl ri
.p2align 3
ri:
.quad _ZGR2ri_
.size ri, 8
What is the reason of such behavior? Is it a bug? The fact that it still replaces all uses of ri
in the same TU by its initial value 5
suggests that it is a bug.
My hypothesis is that in [dcl.init.ref]/5.2
If the converted initializer is a prvalue, its type T4 is adjusted to type “cv1 T4” ([conv.qual]) and the temporary materialization conversion is applied.
it naïvely discards (or rather do not add) the cv1
-qualifier from (to) the prvalue type.
The funny thing is that if replace the initializer expression with a prvalue of non-reference-related, but convertible type
const int& ri = 5.0;
it starts to put the object with the value 5
into the .rodata
section again.
Is there anything in the standard that now requires such mutability? In other words:
- it the object designated by
ri
modifiable by conforming code? (obviously code involving UB could try to change it and the compiler isn't required to make effort to allow that) - is the storage of that object modifiable by conforming code, by reusing it to create another object of a size no bigger than the size of the temporary "aliased" ("references are aliases") by the
ri
that issizeof (int)
?