[cxx-abi-dev] need mangling for string literals and lifetime-extended temporaries used in static constexpr member initializers and for string literals in constexpr functions

John McCall rjmccall at apple.com
Fri May 24 19:53:38 UTC 2013


On May 24, 2013, at 2:21 AM, Gabriel Dos Reis <gdr at integrable-solutions.net> wrote:
> On Fri, May 24, 2013 at 3:10 AM, John McCall <rjmccall at apple.com> wrote:
>> On May 23, 2013, at 11:29 PM, Richard Smith <richardsmith at google.com> wrote:
>> 
>> On Thu, May 23, 2013 at 10:41 PM, John McCall <rjmccall at apple.com> wrote:
>>> 
>>> On May 23, 2013, at 10:23 PM, Richard Smith <richardsmith at google.com>
>>> wrote:
>>>> So... this problem was not really new in C++11. In C++98 it can be
>>>> witnessed for an inline function such as:
>>>> 
>>>> inline const char *get() {
>>>>  static const char *str = "foo";
>>>>  return str;
>>>> }
>>> 
>>> How is this different from the following?
>>> 
>>>  inline const char *get_nostatic() { return "foo"; }
>>> 
>>> or
>>> 
>>>  inline const char *get_separate() {
>>>    const char *temp = "foo";
>>>    static const char *str = tmp;
>>>    return str;
>>>  }
>>> 
>>> Please find or add something in the standard which will allow us to
>>> not export a symbol for every string literal(*) that happens to be used
>>> in a function with weak linkage.
>> 
>> 
>> Finding failed. In addition to the implications of the ODR, we have this:
>> 
>> [dcl.fct.spec]p4: "A string literal in the body of an extern inline function
>> is the same object in different translation units."
>> 
>> 
>> This is a really terrible language requirement.  Does anyone actually do
>> what's necessary for this?
> 
> It has been in C++ for over 2 decades, if I remember correctly.
> 
> Here is a testcase -- which is handled properly by G++.
> There are 4 translation units involved.

Three, sir.

> 1.  a.h contains only
> 
> inline const char*
> get_sptr() {
>   static const char* s = "foo";
>   return s;
> }
> 
> 2. a1.C includes a.h and defines f1:
> #include "a.h"
> 
> const char* f1() {
>   return get_sptr();
> }
> 
> 
> 3. a2.C includes a.h and defines f2:
> #include "a.h"
> 
> const char* f2() {
>   return get_sptr();
> }
> 
> 
> 4. b.C includes <assert.h> but not a.h, calls f1, f2 in main() with an
> assertion:
> #include <assert.h>
> 
> const char* f1();
> const char* f2();
> 
> int main() {
>   assert(f1() == f2());
> }
> 
> 
> Now, compile the translation units obtained form a1.C, a2.C, and b.C
> separately, and link them.  The assertion should pass.  G++ on x86
> and x86_64 handles that properly.

See, this is tricky.  Does it handle it properly, or does it happen to work
because the linker combines strings within a linkage unit?

>> I really can't imagine actually implementing it;
>> it would be a *ton* of new extern symbols.
> 
> Only if the string literals escape their enclosing functions.

In practice, almost every string literal escapes its enclosing function.
  printf("foo\n"); // <-- unless the compiler hard-codes printf, this is an escape

John.


More information about the cxx-abi-dev mailing list