[cxx-abi-dev] Literal operator functions with 'li<length, ID>'

Mike Herrick mjh at edg.com
Fri Aug 9 15:42:47 UTC 2013


On Aug 7, 2013, at 3:26 PM, Richard Smith <richardsmith at google.com> wrote:

> One follow-up related to the example that is given above; our UDL mangling produces a slightly different mangled name for this example: _Z1fIiEDTcmclL_Zli2_wPKcELA4_S0_EEfp_ET_, reflecting a difference in the cv-qualification of the type of the argument that is being passed to the literal operator.  Clang's demangled name reflects the use of "char [4]" as the argument type and we're using "const char [4]":
> 
> < decltype(((operator "" _w((char [4])"..."),param#1))) f<int>(T1)
> ---
> > decltype(((operator "" _w((const char [4])"..."),param#1))) f<int>(T1)
> 
> From a Standards point-of-view, we think "const char [4]" is correct here (the call to a raw literal operator X is defined to be equivalent to operator "" X("n"), and the type of "n" is "array of const char").  Is this a clang bug or the result of some implicit conversion (and if so, should it be reflected in the mangling)?
> 
> It looks like this was a transient bug -- I agree that your mangling is the correct one, and it's also the one that Clang trunk produces. 

Thanks for that confirmation.

Another discrepancy seems to be in the use of <unresolved-name> production.  For example:

  typedef __SIZE_TYPE__ size_t;
  void *operator "" _s(unsigned long long) {}
  void *operator new(size_t) {}
  void *f(unsigned long long) {}
  template<typename T> auto f1(T x)->decltype(operator "" _s(x));
  template<typename T> auto f2(T x)->decltype(operator new(x));
  template<typename T> auto f3(T x)->decltype(f(x));
  int main() {
    f1(0);  // neither g++ nor clang use <unresolved-name> for operator "" _s
            // g++:      _Z2f1IiEDTclli2_sfp_EET_
            // clang:    _Z2f1IiEDTclli2_sfp_EET_
            // expected: _Z2f1IiEDTclonli2_sfp_EET_
    f2(0);  // g++ uses <unresolved-name> for operator new
            // g++:      _Z2f2IiEDTclonnwfp_EET_
            // clang:    _Z2f2IiEDTclnwfp_EET_
            // expected: _Z2f2IiEDTclonnwfp_EET_
    f3(0);  // g++ and clang use <unresolved-name> for f
            // g++:      _Z2f3IiEDTcl1ffp_EET_
            // clang:    _Z2f3IiEDTcl1ffp_EET_
            // expected: _Z2f3IiEDTcl1ffp_EET_
  }

[Mangled names are from g++ 4.8.1 and clang 3.3.]   We believe <unresolved-name> should be used for all of these cases.

There's another issue here: demangling the "li" <operator-name>.  Each <operator-name> has an implied number of arguments (except the vendor extended operator where the number is explicitly supplied), but a literal operator can have zero, one or two arguments, so it's not clear which of these applies:

  <expression> ::= <unary operator-name> <expression>
               ::= <binary operator-name> <expression> <expression>

Though GNU cxxfilt (from binutils 2.23) demangles the two names in this example properly:

  typedef __SIZE_TYPE__ size_t;
  void operator "" _s(const char *) {}
  void operator "" _s(const char *, size_t) {}
  template<typename T> auto f1(T x)->decltype(operator "" _s(x));
  template<typename T> auto f2(T x)->decltype(operator "" _s(x, 0));
  int main() {
    f1("xyz");  // _Z2f1IPKcEDTclli2_sfp_EET_
    f2("xyz");  // _Z2f2IPKcEDTclli2_sfp_Li0EEET_
  }

Note that if the <unresolved-name> mangling is used here (i.e., with "clonli" rather than "clli"), there's no issue with the arguments because <unresolved-name> (rather than <unary/binary operator-name>) is used as the first argument to the "cl" and the remaining <expressions> are parsed as arguments to the "cl" (not the "li").  That's also the case with mangled names of the form "clL_Zli2_x..." (where <expr-primary> is used for the first "cl" <expression>").

An observation: because the "li" mangling always involves mangling of the implicit call to the literal operator, and the "cl" mangling already handles a variable number of <expression>s, we need to ensure that the arguments to the literal operator are demangled by the "cl" production, not the "li" production; i.e., either we don't produce mangled names with "clli" (because <unresolved-name> or <expr-primary> should instead be used), or we make a special case for "li" that it effectively takes zero <expression> arguments:

	<expression> ::= <nullary operator-name>	# literal operand (no arguments)

I'd prefer the first of these options (I haven't seen an example where the "clli" mangling makes sense), but I think demanglers need to implement the second option in order to deal with existing practice.

Mike Herrick
Edison Design Group


More information about the cxx-abi-dev mailing list