> On Dec 1, 2014, at 2:18 PM, Richard Smith <[email protected]> wrote:
>
> On 1 December 2014 at 12:02, John McCall <[email protected]
> <mailto:[email protected]>> wrote:
> > On Nov 25, 2014, at 6:13 PM, Richard Smith <[email protected]
> > <mailto:[email protected]>> wrote:
> >
> > N4198 (accepted at Urbana) makes it possible for a template parameter of
> > type T U::* to have a template argument of type T V::*, where V is a base
> > class of U or vice versa. A naive attempt to apply the existing ABI rules
> > leads to mangling collisions in cases like this:
> >
> > struct A { int n; };
> > struct B : A {};
> > template<int A::*> void f() {}
> > template<int B::*> void f() {}
> > void g() {
> > constexpr int A::*p = &A::n;
> > constexpr int B::*q = p;
> > f<p>();
> > f<q>();
> > }
> >
> > (Here, a naive approach would use XadL_ZN1A1nEEE as the template argument
> > value in both calls.)
> >
> > In order to resolve this, I suggest we introduce a new mangling for the
> > case of a member pointer template argument where the class containing the
> > member is different from the class in the template parameter. The minimal
> > information we'll need to include is the class in the template parameter
> > and a designator if the base class is a repeated base class.
> >
> > One approach would be to use
> >
> > sc <type> ad L<member>E
> >
> > and to explicitly include the final type plus those intermediate types that
> > introduce multiple inheritance from the base class (that is, just enough to
> > uniquely identify the path).
> >
> > Another would be to introduce a new mangling that incorporates the final
> > type and an offset or discriminator.
>
> Do we have the same problem for references and pointers to base subobjects?
> Okay, I see that the answer is “no”, but only because you kept that
> restriction in N4198. I think we can assume that that’s not permanent.
>
> I agree; I expect we'll eventually pare back the restrictions to something
> like "no pointers/references to union members, and no one-past-the-end
> pointers", or even remove all restrictions altogether if no-one gets upset
> that different template arguments can compare equal. (We've actually already
> crossed this bridge by specifying that pointers to members of a union compare
> equal even if they point to different members, but no-one has got upset about
> it yet...)
>
> I like the idea of using (possibly invented) static_casts; it’s not optimally
> compact, but it at least theoretically works with existing demanglers. Have
> you checked to see if it actually works?
>
> For _Z1fIXscM1BiadL_ZN1A1nEEEEvv (from my example above):
>
> GCC's c++filt gives void f<static_cast<int B::*>(&A::n)>()
> libc++abi's demangler gives void f<static_cast<int B::*>(&(A::n))>() ...
> which is wrong, but it's equally wrong without the static_cast.
Awesome.
> I agree with only including those intermediate steps necessary to uniquely
> determine the path.
>
> We’d have to specify in what dependent situations we include the path.
> “Never” is the easiest answer, so that in
> template <class T, int T::*member> void foo(decltype(T() + temp<&A::baz>());
> we’d mangle &A::baz without a path clarification even if we could type-check
> "temp<&A::baz>()” at template definition time.
>
> That seems reasonable to me, but I'm not exactly sure what classifies as a
> "dependent situation"; do you mean that we should mangle the path only if the
> <template-arg> is not nested within an instantiation-dependent <expression>?
Good question. We get this same issue with integer template arguments: the
expression 1 has type int, but <1> (sometimes) gets mangled with the template
parameter type to which it’s been coerced. I don’t think the ABI completely
specifies when to use one or the other — it’s an example of one of the few
places where “mangle the token stream” isn’t really enough information — but I
feel like the same rule should clearly apply here.
The simplest rule is probably “only mangle using the coerced type when
identifying a concrete specialization, as in the <name> of an <encoding>”.
However, I suspect that Clang, at least, probably aggressively uses the coerced
type whenever it's already type-checked the template arguments, meaning
probably whenever the reference isn’t (some kind of) dependent.
> There's another issue that we should probably fix at the same time:
> qualification conversions are permitted in template arguments, and we
> currently mangle a signature that performs a qualification conversion the
> same way as we mangle a signature that does not. We could either fold the
> qualification conversion into the last (synthetic) static_cast, or add an
> explicit synthetic const_cast to model it. I'm inclined to favour the latter,
> even though it will give longer manglings in the (hopefully rare) case where
> both conversions occur (because it also works if the user has cast away
> constness, and because it's simpler). Example:
>
> // tu1
> extern int n;
> template<int*> void f() {}
> void g() { f<&n>(); }
>
> // tu2
> extern int n;
> template<const int*> void f() {}
> void h() { f<&n>(); }
>
> Here:
> g calls _Z1fIXadL_Z1nEEEvv
> h calls _Z1fIXccPKiadL_Z1nEEEvv
Is this a compatibility issue? As in, aren’t qualification conversions already
allowed in template arguments? There might be a significant number of existing
template arguments that, say, bind a non-const global to a const reference.
John._______________________________________________
cxx-abi-dev mailing list
[email protected]
http://sourcerytools.com/cgi-bin/mailman/listinfo/cxx-abi-dev