Decltype mangling and type dependency

Mike Herrick mjh at edg.com
Tue May 18 00:20:40 UTC 2010


Jason has added many new rules to support the mangling of expressions in decltypes, and I'd like to get some clarification on how and when to apply some of these new rules.

Generally speaking, the idea is to provide a mangling for entities that don't have a "describable" type (https://www.codesourcery.com/archives/cxx-abi-dev/msg01984.html).  In that vein, rules were added to <expression> to handle cases such as:

  struct A {
    int m;
  } *pa;
  int f(void);
  template <class T> auto f1(T p1) -> decltype(p1->m); // _Z2f1IP1AEDtptfp_1mET_
  template <class T> auto f2(T p1) -> decltype(p1());  // _Z2f2IPFivEEDTclfp_EET_
  int main() {
    f1(pa);
    f2(f);
  }

As a general rule, expressions (that appear in decltype/sizeof/alignof) with dependent types are mangled in full (using the newly added rules), while expressions with non-dependent types simply use the expression type.

But what about these similar cases:

  struct A {
    int m;
  } *pa;
  int f(void);
  template <class T> auto f1(T p1) -> decltype(pa->m); // _Z2f1IP1AEDtptL_Z2paE1mET_ or _Z2f1IP1AEiT_?
  template <class T> auto f2(T p1) -> decltype(f());   // _Z2f2IPFivEEDTclL_Z1fvEEET_ or _Z2f2IPFivEEiT_?
  int main() {
    f1(pa);
    f2(f);
  }

Since the types of pa->m and f are non-dependent, is it required to mangle these with the full decltype expression mangling (as g++ 4.5 currently does)?

Here are some other interesting cases:

  #include <typeinfo>
  struct A {
    A();
    A(int i);
    int m;
  } a;
  int f();
  template <class T> auto f1(T p1) -> decltype(p1);
  template <class T> auto f2(T p1) -> decltype(A(p1));
  template <class T> auto f3(T p1) -> decltype(typeid(p1));
  template <class T> auto f4(T p1) -> decltype(a.m);
  template <class T> auto f5(T p1) -> decltype(a.A::m);
  int main() {
    f1(0);
    f2(0);
    f3(0);
    f4(0);
    f5(0);
  }

We believe f1, f2, and f3 require decltype manglings, while f4 and f5 do not (g++ 4.5 takes the opposite view on each of these).  Even though the typeid expression in f3 above is not type-dependent (always returning an lvalue of const std::type_info regardless of its argument), it can still be used in ways where a distinct mangling is required; for example:

  template <class T> auto f(T p) -> decltype(g(typeid(p))) { ... }
  template <class T> auto f(T p) -> decltype(g(typeid(*p))) { ... }

Similarly, we believe that constructors can be used in ways that require a full dependent mangling, as shown by this "if it's valid, it always means one thing, but it might not be valid, which means new-style SFINAE could knock it out of the candidate set" example:

  template <class T> auto f(T p) -> decltype(A(p)) { ... }
  template <class T> auto f(T p) -> decltype(A(p, 5)) { ... }

This seems to argue for a third designation, "partially-dependent", for cases where the expression type is non-dependent, but because of the new SFINAE rules, it can be distinguished by the programmer and therefore requires a distinct mangling (as though it were dependent).

Mike Herrick
Edison Design Group



More information about the cxx-abi-dev mailing list