This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 116a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-12-19


2753. Storage reuse for string literal objects and backing arrays

Section: 6.7.2  [intro.object]     Status: DRWP     Submitter: Brian Bi     Date: 2023-06-29

[Accepted as a DR at the November, 2023 meeting.]

Subclause 6.7.2 [intro.object] paragraph 9 specifies the general principle that two objects with overlapping lifetimes have non-overlapping storage, which can be observed by comparing addresses:

Unless an object is a bit-field or a subobject of zero size, the address of that object is the address of the first byte it occupies. Two objects with overlapping lifetimes that are not bit-fields may have the same address if one is nested within the other, or if at least one is a subobject of zero size and they are of different types; otherwise, they have distinct addresses and occupy disjoint bytes of storage.

After P2752, there are two exceptions: string literal objects and backing arrays for initializer lists.

Subclause 5.13.5 [lex.string] paragraph 9 specifies:

Evaluating a string-literal results in a string literal object with static storage duration (6.7.6 [basic.stc]). Whether all string-literals are distinct (that is, are stored in nonoverlapping objects) and whether successive evaluations of a string-literal yield the same or a different object is unspecified.

Subclause 9.4.4 [dcl.init.ref] paragraph 5, after application of P2752R3 (approved in June, 2023), specifies:

Whether all backing arrays are distinct (that is, are stored in non-overlapping objects) is unspecified.

It is unclear whether a backing array can overlap with a string literal object.

Furthermore, it is unclear whether any such object can overlap with named objects or temporaries, for example:

  const char (&r) [] = "foo";
  const char a[] = {'f', 'o', 'o', '\0'};

  int main() {  
    assert(&r == &a);   // allowed not to fail?
  }

Proposed resolution (approved by CWG 2023-11-09):

  1. Add a new paragraph before 6.7.2 [intro.object] paragraph 9 and change the latter as follows:

    An object is a potentially non-unique object if it is a string literal object (5.13.5 [lex.string]), the backing array of an initializer list (9.4.4 [dcl.init.ref]), or a subobject thereof.

    Unless an object is a bit-field or a subobject of zero size, the address of that object is the address of the first byte it occupies. Two objects with overlapping lifetimes that are not bit-fields may have the same address if one is nested within the other, or if at least one is a subobject of zero size and they are of different types, or if they are both potentially non-unique objects; otherwise, they have distinct addresses and occupy disjoint bytes of storage.

    [Example 2:

      static const char test1 = 'x';
      static const char test2 = 'x';
      const bool b = &test1 != &test2;  // always true
    
      static const char (&r) [] = "x";
      static const char *s = "x";  
      static std::initializer_list<char> il = { 'x' };
      const bool b2 = r != il.begin();        // unspecified result
      const bool b3 = r != s;                 // unspecified result
      const bool b4 = il.begin() != &test1;   // always true
      const bool b5 = r != &test1;            // always true
    

    -- end example]

  2. Change in subclause 5.13.5 [lex.string] paragraph 9 as follows:

    Evaluating a string-literal results in a string literal object with static storage duration (6.7.6 [basic.stc]). [ Note: String literal objects are potentially non-unique (6.7.2 [intro.object]). Whether all string-literals are distinct (that is, are stored in nonoverlapping objects) and whether successive evaluations of a string-literal yield the same or a different object is unspecified. -- end note ]
  3. Change in subclause 9.4.4 [dcl.init.ref] paragraph 5, after application of P2752R3 (approved in June, 2023), as follows:

    Whether all backing arrays are distinct (that is, are stored in non-overlapping objects) is unspecified. [ Note: Backing arrays are potentially non-unique objects (6.7.2 [intro.object]). -- end note ]

CWG 2023-07-14

CWG resolved that a named or temporary object is always disjoint from any other object, and thus cannot overlap with a string literal object or a backing array. The lines b4 and b5 in the example highlight that outcome.

Backing arrays and string literals can arbitrarily overlap among themselves; CWG believes the proposed wording achieves that outcome.

The ancillary question how address comparisons between potentially non-unique objects are treated during constant evaluation is handled in issue 2765.