[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:57:06 UTC 2013


On May 24, 2013, at 12:53 PM, John McCall <rjmccall at apple.com> wrote:
> 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?

Also, the requirement I'm complaining about here is *not* the
"static local in an inline context" requirement.  Obviously that's
crucial to implement correctly.

The requirement I'm complaining about is that arguably your
example is guaranteed to work even if get_sptr() is implemented
thusly:

  inline const char *get_sptr() { return "foo"; }

Because it's a string literal in an extern inline function and so it's
the same object.

John.


More information about the cxx-abi-dev mailing list