[cxx-abi-dev] mangling for c++17 decomposition declarations

John McCall rjmccall at apple.com
Sat Aug 13 02:35:03 UTC 2016


> On Aug 12, 2016, at 6:06 PM, Richard Smith <richardsmith at google.com> wrote:
> On 12 August 2016 at 17:29, John McCall <rjmccall at apple.com <mailto:rjmccall at apple.com>> wrote:
> > On Aug 12, 2016, at 4:59 PM, Richard Smith <richardsmith at google.com <mailto:richardsmith at google.com>> wrote:
> >
> > C++17 decomposition declarations are (surprisingly) permitted at global scope. They can't be forward-declared nor made inline (yet...), and it seems likely that the wording probably didn't *mean* to allow them to be declared as templates, so we don't appear to need a cross-vendor mangling for them. However, establishing a convention would be useful for demanglers.
> >
> > For now, I'm mangling global decomposition declarations as:
> >
> >   <unqualified-name> ::= DC <source-name>* E
> >
> > ... where the <source-name>s are the names of the bindings. (I'm mangling the bindings in the obvious way, as if they were reference declarations, but they get a mangled name even at global scope.)
> >
> > We could get away with mangling only the name of the first binding, but the extra information seems useful to people looking at the mangled name.
> >
> > Thoughts? Is it worth specifying this in the ABI?
> 
> For those of us who aren't following the standards process that closely, would you mind explaining the more basic ABI impact of the feature?  Are the individual bindings separate objects that should be mangled as it they were actually declared separately, and so this compound mangling only serves to uniquely identify the initializer in case it contains entities that need / ought to be mangled?
> 
> Yes, but the bindings are always of reference type when they exist at all. In a decomposition declaration like:
> 
>   auto [a, b, c] = expr;
> 
> there are (potentially, see below) four distinct entities: a variable
> 
>   auto e = expr;
> 
> and three bindings (a, b, and c). The mangling above would be used for the 'e' variable. There is no way to reference that implicit variable except through the bindings.

Ah, so it's not like you can declare a bunch of separate extern variables and then define them using a single decomposition binding; it really is a sort of inherently different declaration that just happens to create multiple names.

> There are two different cases for the behavior of the bindings: either they are built-in bindings representing some subobject of e (including bitfield members)

What.

I mean, okay, it's not actually unreasonable for the language to start taking advantage of the nature of reference-binding to do things like this, but it is surprising to sneak it in this way.  Have they lifted the restrictions on local reference-binding as well?  Obviously they can't be lifted for parameter binding, but there's no reason you couldn't bind a local reference to a bit-field; it's just implementation complexity.

> with no corresponding entity, or (for types like std::tuple) they act as variables of reference type initialized by some user-specified expression which can have arbitrary side-effects (the corresponding extension mechanism involves specializing standard-library templates and providing a function template to be found by ADL, and has no ABI impact).
> 
> For the built-in case, it seems most straightforward to not generate globals at all (and emit references to a, b, and c directly as references to the corresponding subobject of e),

This is essentially required to handle bit-fields, at least.

The value being decomposed by a builtin binding has to be a pr-value, right?  Or gets coerced to one?  Or is the model really just as simple as "there's an object initialized by this expression, and these names are bound to sub-objects of it".

> but for the user-defined extension case, code is run to initialize the bindings and they generally need to act like global variables. A pedantic reading of the standard suggests that you could do this:
> 
>   auto [a] = std::tuple<int>(0); // tu1.cc
> 
>   extern int &&a; // tu2.cc
> 
> ... which would certainly restrict the ABI choices, but I don't think that was an intended consequence of the rules.

If this is formally allowed, I don't see why

  extern int &&a, &&b;
  auto [a,b] = std::make_pair(1,2);

wouldn't be.  But of course this cannot be made to support bit-field references without breaking ABI.

> There is (currently) no way to declare the same decomposition declaration across multiple translation units (there's a syntactic limitation preventing them from being static locals, inline globals, or static data members), so in that sense there is no formal ABI impact.

Ok.

John.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://sourcerytools.com/pipermail/cxx-abi-dev/attachments/20160812/c1a47fdb/attachment-0001.html>


More information about the cxx-abi-dev mailing list