From daveed at edg.com Tue Oct 4 11:25:33 2016 From: daveed at edg.com (David Vandevoorde) Date: Tue, 4 Oct 2016 07:25:33 -0400 Subject: [cxx-abi-dev] std::type_info::hash_code/before Message-ID: <9B554541-893F-40BC-B8A9-CDAD41457745@edg.com> Shouldn't the ABI document specify how type_info entries are collated and hashed with their before() and hash_code() members? Daveed From rjmccall at apple.com Tue Oct 4 20:22:15 2016 From: rjmccall at apple.com (John McCall) Date: Tue, 4 Oct 2016 13:22:15 -0700 Subject: [cxx-abi-dev] std::type_info::hash_code/before In-Reply-To: <9B554541-893F-40BC-B8A9-CDAD41457745@edg.com> References: <9B554541-893F-40BC-B8A9-CDAD41457745@edg.com> Message-ID: > On Oct 4, 2016, at 4:25 AM, David Vandevoorde wrote: > Shouldn't the ABI document specify how type_info entries are collated and hashed with their before() and hash_code() members? Yes, that seems reasonable. It's only necessary for interoperation of multiple standard libraries on a platform, but that's a thing. Since the ABI only formally guarantees that the names are uniqued, I think the obviously correct way of implementing these is to compare name pointers in before() and reinterpret the name pointer as the result of hash_code(). That is what libc++ seems to do. I don't have a recent libstdc++ header around; the ancient one I do have uses that rule for before() and doesn't implement hash_code(), but IIRC these days libstdc++ uses a variant ABI for type_info anyway. Darwin ARM64 uses a variant ABI that does not guarantee that names are uniqued, and so we need a different rule there to handle that; in particular, it does actually have to fall back on string comparisons and string hashes for non-unique type info. John. From richardsmith at googlers.com Tue Oct 4 21:11:12 2016 From: richardsmith at googlers.com (Richard Smith) Date: Tue, 4 Oct 2016 14:11:12 -0700 Subject: [cxx-abi-dev] std::type_info::hash_code/before In-Reply-To: References: <9B554541-893F-40BC-B8A9-CDAD41457745@edg.com> Message-ID: On 4 October 2016 at 13:22, John McCall wrote: > > On Oct 4, 2016, at 4:25 AM, David Vandevoorde wrote: > > Shouldn't the ABI document specify how type_info entries are collated > and hashed with their before() and hash_code() members? > > Yes, that seems reasonable. It's only necessary for interoperation of > multiple standard libraries on a platform, but that's a thing. > > Since the ABI only formally guarantees that the names are uniqued, I think > the obviously correct way of implementing these is to compare name pointers > in before() and reinterpret the name pointer as the result of hash_code(). > That is what libc++ seems to do. I don't have a recent libstdc++ header > around; the ancient one I do have uses that rule for before() and doesn't > implement hash_code(), but IIRC these days libstdc++ uses a variant ABI for > type_info anyway. > libstdc++ has two modes: in one mode, it guarantees typeinfo name uniqueness across the program, uses the pointer for before(), and reinterprets the pointer as a hash for hash_code. In the other mode (where they try to merge types from a .so even if it was dlopen'd RTLD_LOCAL [1]), some names are unique and others are not; hash_code computes a hash of the name, and before ... well, before is broken, and doesn't produce a strict weak order. [1]: It would seem reasonable for the ABI document to say something about what happens in this case. If I understand correctly, the issue is that a .so that's dlopen'd RTLD_LOCAL can contain a weak definition of the type_info for a type that's logically part of another library, and if it's loaded before that other library is, the type_info name doesn't get merged despite there being some intent that it's the same type. Darwin ARM64 uses a variant ABI that does not guarantee that names are > uniqued, and so we need a different rule there to handle that; in > particular, it does actually have to fall back on string comparisons and > string hashes for non-unique type info. > > John. > _______________________________________________ > cxx-abi-dev mailing list > cxx-abi-dev at codesourcery.com > http://sourcerytools.com/cgi-bin/mailman/listinfo/cxx-abi-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rjmccall at apple.com Tue Oct 4 21:54:18 2016 From: rjmccall at apple.com (John McCall) Date: Tue, 4 Oct 2016 14:54:18 -0700 Subject: [cxx-abi-dev] std::type_info::hash_code/before In-Reply-To: References: <9B554541-893F-40BC-B8A9-CDAD41457745@edg.com> Message-ID: <1D16C6B7-B531-426F-B372-010DC7B0FB97@apple.com> > On Oct 4, 2016, at 2:11 PM, Richard Smith wrote: > > On 4 October 2016 at 13:22, John McCall > wrote: > > On Oct 4, 2016, at 4:25 AM, David Vandevoorde > wrote: > > Shouldn't the ABI document specify how type_info entries are collated and hashed with their before() and hash_code() members? > > Yes, that seems reasonable. It's only necessary for interoperation of multiple standard libraries on a platform, but that's a thing. > > Since the ABI only formally guarantees that the names are uniqued, I think the obviously correct way of implementing these is to compare name pointers in before() and reinterpret the name pointer as the result of hash_code(). That is what libc++ seems to do. I don't have a recent libstdc++ header around; the ancient one I do have uses that rule for before() and doesn't implement hash_code(), but IIRC these days libstdc++ uses a variant ABI for type_info anyway. > > libstdc++ has two modes: in one mode, it guarantees typeinfo name uniqueness across the program, uses the pointer for before(), and reinterprets the pointer as a hash for hash_code. In the other mode (where they try to merge types from a .so even if it was dlopen'd RTLD_LOCAL [1]), some names are unique and others are not; hash_code computes a hash of the name, and before ... well, before is broken, and doesn't produce a strict weak order. Is this set by environment variable or by #define? I suppose the latter would technically work if done consistently enough in program code to paper over the ODR problems, since the parts of the ABI library that do type_info comparisons (for dynamic_cast and exceptions) are unlikely to use either before() or hash_code(). > [1]: It would seem reasonable for the ABI document to say something about what happens in this case. If I understand correctly, the issue is that a .so that's dlopen'd RTLD_LOCAL can contain a weak definition of the type_info for a type that's logically part of another library, and if it's loaded before that other library is, the type_info name doesn't get merged despite there being some intent that it's the same type. I suppose I can't just say that that's an ELF problem. :) What we did for ARM64 seems like the right basic approach: the type_info object records whether it's unique or non-unique, and non-unique RTTI just falls back on string-based comparisons / hashes. The type_info is unique if and only if it's for a fundamental type in the ABI library or a polymorphic class with a key function. John. > > Darwin ARM64 uses a variant ABI that does not guarantee that names are uniqued, and so we need a different rule there to handle that; in particular, it does actually have to fall back on string comparisons and string hashes for non-unique type info. > > John. > _______________________________________________ > cxx-abi-dev mailing list > cxx-abi-dev at codesourcery.com > http://sourcerytools.com/cgi-bin/mailman/listinfo/cxx-abi-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From daveed at edg.com Tue Oct 4 22:06:20 2016 From: daveed at edg.com (David Vandevoorde) Date: Tue, 4 Oct 2016 18:06:20 -0400 Subject: [cxx-abi-dev] std::type_info::hash_code/before In-Reply-To: <1D16C6B7-B531-426F-B372-010DC7B0FB97@apple.com> References: <9B554541-893F-40BC-B8A9-CDAD41457745@edg.com> <1D16C6B7-B531-426F-B372-010DC7B0FB97@apple.com> Message-ID: <4187C7E1-6F2B-4158-9699-AD5F2AAAC926@edg.com> > On Oct 4, 2016, at 5:54 PM, John McCall wrote: [?] > What we did for ARM64 seems like the right basic approach: the type_info object records whether it's unique or non-unique, and non-unique RTTI just falls back on string-based comparisons / hashes. The type_info is unique if and only if it's for a fundamental type in the ABI library or a polymorphic class with a key function. That sounds pretty good, but can it be done in a backward-compatible way? I?m guessing not, but perhaps it?s ?close enough?? Daveed -------------- next part -------------- An HTML attachment was scrubbed... URL: From rjmccall at apple.com Tue Oct 4 22:18:47 2016 From: rjmccall at apple.com (John McCall) Date: Tue, 4 Oct 2016 15:18:47 -0700 Subject: [cxx-abi-dev] std::type_info::hash_code/before In-Reply-To: <4187C7E1-6F2B-4158-9699-AD5F2AAAC926@edg.com> References: <9B554541-893F-40BC-B8A9-CDAD41457745@edg.com> <1D16C6B7-B531-426F-B372-010DC7B0FB97@apple.com> <4187C7E1-6F2B-4158-9699-AD5F2AAAC926@edg.com> Message-ID: > On Oct 4, 2016, at 3:06 PM, David Vandevoorde wrote: >> On Oct 4, 2016, at 5:54 PM, John McCall > wrote: > [?] >> What we did for ARM64 seems like the right basic approach: the type_info object records whether it's unique or non-unique, and non-unique RTTI just falls back on string-based comparisons / hashes. The type_info is unique if and only if it's for a fundamental type in the ABI library or a polymorphic class with a key function. > > That sounds pretty good, but can it be done in a backward-compatible way? I?m guessing not, but perhaps it?s ?close enough?? If you still made every effort to coalesce type_info names even for non-unique RTTI, and you found a way to record non-uniqueness that didn't mess up existing compiles, then interoperation would generally remain intact. However, in my mind that would sacrifice the main benefit, which is that non-unique RTTI no longer require default visibility. I should have been clear that I was noting this mostly as an "ABI v2" recommendation. John. -------------- next part -------------- An HTML attachment was scrubbed... URL: From richardsmith at googlers.com Tue Oct 4 22:19:17 2016 From: richardsmith at googlers.com (Richard Smith) Date: Tue, 4 Oct 2016 15:19:17 -0700 Subject: [cxx-abi-dev] std::type_info::hash_code/before In-Reply-To: <1D16C6B7-B531-426F-B372-010DC7B0FB97@apple.com> References: <9B554541-893F-40BC-B8A9-CDAD41457745@edg.com> <1D16C6B7-B531-426F-B372-010DC7B0FB97@apple.com> Message-ID: On 4 October 2016 at 14:54, John McCall wrote: > > On Oct 4, 2016, at 2:11 PM, Richard Smith > wrote: > > On 4 October 2016 at 13:22, John McCall wrote: > >> > On Oct 4, 2016, at 4:25 AM, David Vandevoorde wrote: >> > Shouldn't the ABI document specify how type_info entries are collated >> and hashed with their before() and hash_code() members? >> >> Yes, that seems reasonable. It's only necessary for interoperation of >> multiple standard libraries on a platform, but that's a thing. >> >> Since the ABI only formally guarantees that the names are uniqued, I >> think the obviously correct way of implementing these is to compare name >> pointers in before() and reinterpret the name pointer as the result of >> hash_code(). That is what libc++ seems to do. I don't have a recent >> libstdc++ header around; the ancient one I do have uses that rule for >> before() and doesn't implement hash_code(), but IIRC these days libstdc++ >> uses a variant ABI for type_info anyway. >> > > libstdc++ has two modes: in one mode, it guarantees typeinfo name > uniqueness across the program, uses the pointer for before(), and > reinterprets the pointer as a hash for hash_code. In the other mode (where > they try to merge types from a .so even if it was dlopen'd RTLD_LOCAL [1]), > some names are unique and others are not; hash_code computes a hash of the > name, and before ... well, before is broken, and doesn't produce a strict > weak order. > > > Is this set by environment variable or by #define? I suppose the latter > would technically work if done consistently enough in program code to paper > over the ODR problems, since the parts of the ABI library that do type_info > comparisons (for dynamic_cast and exceptions) are unlikely to use either > before() or hash_code(). > It looks like it's a libsupc++ configure-time #define. > [1]: It would seem reasonable for the ABI document to say something about > what happens in this case. If I understand correctly, the issue is that a > .so that's dlopen'd RTLD_LOCAL can contain a weak definition of the > type_info for a type that's logically part of another library, and if it's > loaded before that other library is, the type_info name doesn't get merged > despite there being some intent that it's the same type. > > > I suppose I can't just say that that's an ELF problem. :) > > What we did for ARM64 seems like the right basic approach: the type_info > object records whether it's unique or non-unique, and non-unique RTTI just > falls back on string-based comparisons / hashes. The type_info is unique > if and only if it's for a fundamental type in the ABI library or a > polymorphic class with a key function. > That's approximately what GCC does. IIRC, you guys use a tag bit for the local/non-local choice, whereas GCC prepends the name with '*' for the case where a pointer comparison is applicable. The tag bit approach seems substantially better, since it doesn't require first fetching through the pointer in order to tell that we didn't actually need to fetch through the pointer :) On the other hand, GCC has a trick you don't mention here: it also treats internal-linkage types has having unique type_info. > John. > > > Darwin ARM64 uses a variant ABI that does not guarantee that names are >> uniqued, and so we need a different rule there to handle that; in >> particular, it does actually have to fall back on string comparisons and >> string hashes for non-unique type info. >> >> John. >> _______________________________________________ >> cxx-abi-dev mailing list >> cxx-abi-dev at codesourcery.com >> http://sourcerytools.com/cgi-bin/mailman/listinfo/cxx-abi-dev >> > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rjmccall at apple.com Tue Oct 4 22:29:55 2016 From: rjmccall at apple.com (John McCall) Date: Tue, 4 Oct 2016 15:29:55 -0700 Subject: [cxx-abi-dev] std::type_info::hash_code/before In-Reply-To: References: <9B554541-893F-40BC-B8A9-CDAD41457745@edg.com> <1D16C6B7-B531-426F-B372-010DC7B0FB97@apple.com> Message-ID: > On Oct 4, 2016, at 3:19 PM, Richard Smith wrote: > On 4 October 2016 at 14:54, John McCall > wrote: > >> On Oct 4, 2016, at 2:11 PM, Richard Smith > wrote: >> >> On 4 October 2016 at 13:22, John McCall > wrote: >> > On Oct 4, 2016, at 4:25 AM, David Vandevoorde > wrote: >> > Shouldn't the ABI document specify how type_info entries are collated and hashed with their before() and hash_code() members? >> >> Yes, that seems reasonable. It's only necessary for interoperation of multiple standard libraries on a platform, but that's a thing. >> >> Since the ABI only formally guarantees that the names are uniqued, I think the obviously correct way of implementing these is to compare name pointers in before() and reinterpret the name pointer as the result of hash_code(). That is what libc++ seems to do. I don't have a recent libstdc++ header around; the ancient one I do have uses that rule for before() and doesn't implement hash_code(), but IIRC these days libstdc++ uses a variant ABI for type_info anyway. >> >> libstdc++ has two modes: in one mode, it guarantees typeinfo name uniqueness across the program, uses the pointer for before(), and reinterprets the pointer as a hash for hash_code. In the other mode (where they try to merge types from a .so even if it was dlopen'd RTLD_LOCAL [1]), some names are unique and others are not; hash_code computes a hash of the name, and before ... well, before is broken, and doesn't produce a strict weak order. > > Is this set by environment variable or by #define? I suppose the latter would technically work if done consistently enough in program code to paper over the ODR problems, since the parts of the ABI library that do type_info comparisons (for dynamic_cast and exceptions) are unlikely to use either before() or hash_code(). > > It looks like it's a libsupc++ configure-time #define. Ah, so basically a platform decision, then. Although I guess it's probably more plausible to swap in your own libsupc++ on Linux than it would be on Darwin. >> [1]: It would seem reasonable for the ABI document to say something about what happens in this case. If I understand correctly, the issue is that a .so that's dlopen'd RTLD_LOCAL can contain a weak definition of the type_info for a type that's logically part of another library, and if it's loaded before that other library is, the type_info name doesn't get merged despite there being some intent that it's the same type. > > I suppose I can't just say that that's an ELF problem. :) > > What we did for ARM64 seems like the right basic approach: the type_info object records whether it's unique or non-unique, and non-unique RTTI just falls back on string-based comparisons / hashes. The type_info is unique if and only if it's for a fundamental type in the ABI library or a polymorphic class with a key function. > > That's approximately what GCC does. IIRC, you guys use a tag bit for the local/non-local choice, whereas GCC prepends the name with '*' for the case where a pointer comparison is applicable. The tag bit approach seems substantially better, since it doesn't require first fetching through the pointer in order to tell that we didn't actually need to fetch through the pointer :) Yep, that's why we did it that way. :) Does GCC just always emit unique RTTI with the '*' prefix, or does it rely on being configured the same way as libsupc++? > On the other hand, GCC has a trick you don't mention here: it also treats internal-linkage types has having unique type_info. Oh, yes, we do that as well. John. -------------- next part -------------- An HTML attachment was scrubbed... URL: From richardsmith at googlers.com Tue Oct 4 22:48:00 2016 From: richardsmith at googlers.com (Richard Smith) Date: Tue, 4 Oct 2016 15:48:00 -0700 Subject: [cxx-abi-dev] std::type_info::hash_code/before In-Reply-To: References: <9B554541-893F-40BC-B8A9-CDAD41457745@edg.com> <1D16C6B7-B531-426F-B372-010DC7B0FB97@apple.com> Message-ID: On 4 October 2016 at 15:29, John McCall wrote: > On Oct 4, 2016, at 3:19 PM, Richard Smith > wrote: > On 4 October 2016 at 14:54, John McCall wrote: > >> >> On Oct 4, 2016, at 2:11 PM, Richard Smith >> wrote: >> >> On 4 October 2016 at 13:22, John McCall wrote: >> >>> > On Oct 4, 2016, at 4:25 AM, David Vandevoorde wrote: >>> > Shouldn't the ABI document specify how type_info entries are collated >>> and hashed with their before() and hash_code() members? >>> >>> Yes, that seems reasonable. It's only necessary for interoperation of >>> multiple standard libraries on a platform, but that's a thing. >>> >>> Since the ABI only formally guarantees that the names are uniqued, I >>> think the obviously correct way of implementing these is to compare name >>> pointers in before() and reinterpret the name pointer as the result of >>> hash_code(). That is what libc++ seems to do. I don't have a recent >>> libstdc++ header around; the ancient one I do have uses that rule for >>> before() and doesn't implement hash_code(), but IIRC these days libstdc++ >>> uses a variant ABI for type_info anyway. >>> >> >> libstdc++ has two modes: in one mode, it guarantees typeinfo name >> uniqueness across the program, uses the pointer for before(), and >> reinterprets the pointer as a hash for hash_code. In the other mode (where >> they try to merge types from a .so even if it was dlopen'd RTLD_LOCAL [1]), >> some names are unique and others are not; hash_code computes a hash of the >> name, and before ... well, before is broken, and doesn't produce a strict >> weak order. >> >> >> Is this set by environment variable or by #define? I suppose the latter >> would technically work if done consistently enough in program code to paper >> over the ODR problems, since the parts of the ABI library that do type_info >> comparisons (for dynamic_cast and exceptions) are unlikely to use either >> before() or hash_code(). >> > > It looks like it's a libsupc++ configure-time #define. > > > Ah, so basically a platform decision, then. Although I guess it's > probably more plausible to swap in your own libsupc++ on Linux than it > would be on Darwin. > > [1]: It would seem reasonable for the ABI document to say something about >> what happens in this case. If I understand correctly, the issue is that a >> .so that's dlopen'd RTLD_LOCAL can contain a weak definition of the >> type_info for a type that's logically part of another library, and if it's >> loaded before that other library is, the type_info name doesn't get merged >> despite there being some intent that it's the same type. >> >> >> I suppose I can't just say that that's an ELF problem. :) >> >> What we did for ARM64 seems like the right basic approach: the type_info >> object records whether it's unique or non-unique, and non-unique RTTI just >> falls back on string-based comparisons / hashes. The type_info is unique >> if and only if it's for a fundamental type in the ABI library or a >> polymorphic class with a key function. >> > > That's approximately what GCC does. IIRC, you guys use a tag bit for the > local/non-local choice, whereas GCC prepends the name with '*' for the case > where a pointer comparison is applicable. The tag bit approach seems > substantially better, since it doesn't require first fetching through the > pointer in order to tell that we didn't actually need to fetch through the > pointer :) > > > Yep, that's why we did it that way. :) > > Does GCC just always emit unique RTTI with the '*' prefix, or does it rely > on being configured the same way as libsupc++? > It looks like it unconditionally emits the '*' for any class that is not accessible from outside the translation unit. (The presence or absence of a key function doesn't seem to make any difference.) > On the other hand, GCC has a trick you don't mention here: it also treats > internal-linkage types has having unique type_info. > > > Oh, yes, we do that as well. > > John. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From hstong at ca.ibm.com Wed Oct 5 18:54:28 2016 From: hstong at ca.ibm.com (Hubert Tong) Date: Wed, 5 Oct 2016 14:54:28 -0400 Subject: [cxx-abi-dev] C++17 mangling for result of lambda conversion function Message-ID: In N4604 subclause 5.1.5 [expr.prim.lambda] paragraph 7, the conversion function to a pointer-to-function is constexpr. This means that the resulting pointer-to-function may be used as a template non-type argument and thus need a mangling. Clang currently mangles as a member of the closure type named __invoke, and GCC seems to use _FUN in place of __invoke. I find the Clang name to be less jarring. -- HT ===== Hubert S. K. Tong IBM Canada Ltd., C2/YGH/8200/MKM 8200 Warden Avenue, Markham, Ontario L6G 1C7, Canada === -------------- next part -------------- An HTML attachment was scrubbed... URL: From richardsmith at googlers.com Wed Oct 5 21:43:12 2016 From: richardsmith at googlers.com (Richard Smith) Date: Wed, 5 Oct 2016 14:43:12 -0700 Subject: [cxx-abi-dev] C++17 mangling for result of lambda conversion function In-Reply-To: References: Message-ID: On 5 October 2016 at 11:54, Hubert Tong wrote: > In N4604 subclause 5.1.5 [expr.prim.lambda] paragraph 7, the conversion > function to a pointer-to-function is constexpr. > This means that the resulting pointer-to-function may be used as a > template non-type argument and thus need a mangling. > > Clang currently mangles as a member of the closure type named __invoke, > and GCC seems to use _FUN in place of __invoke. > I find the Clang name to be less jarring. > I'd be fine with specifying either of these, or with some new custom mangling. I note that EDG uses the _FUN mangling, like GCC, but unlike GCC and Clang, does not make the name visible to class member name lookup. -------------- next part -------------- An HTML attachment was scrubbed... URL: From daveed at edg.com Wed Oct 5 22:32:19 2016 From: daveed at edg.com (David Vandevoorde) Date: Wed, 5 Oct 2016 18:32:19 -0400 Subject: [cxx-abi-dev] C++17 mangling for result of lambda conversion function In-Reply-To: References: Message-ID: <71B6D0AE-CB58-4F2F-B083-9451652536D6@edg.com> > On Oct 5, 2016, at 5:43 PM, Richard Smith wrote: > > On 5 October 2016 at 11:54, Hubert Tong > wrote: > In N4604 subclause 5.1.5 [expr.prim.lambda] paragraph 7, the conversion function to a pointer-to-function is constexpr. > This means that the resulting pointer-to-function may be used as a template non-type argument and thus need a mangling. > > Clang currently mangles as a member of the closure type named __invoke, and GCC seems to use _FUN in place of __invoke. > I find the Clang name to be less jarring. > > I'd be fine with specifying either of these, or with some new custom mangling. I note that EDG uses the _FUN mangling, like GCC, but unlike GCC and Clang, does not make the name visible to class member name lookup. Except in our GNU and Clang C++ modes, where we do make the name visible ;-) (Our Clang-mode behavior is accidental in this regard, though.) Daveed -------------- next part -------------- An HTML attachment was scrubbed... URL: From richardsmith at googlers.com Wed Oct 5 22:38:37 2016 From: richardsmith at googlers.com (Richard Smith) Date: Wed, 5 Oct 2016 15:38:37 -0700 Subject: [cxx-abi-dev] C++17 mangling for result of lambda conversion function In-Reply-To: <71B6D0AE-CB58-4F2F-B083-9451652536D6@edg.com> References: <71B6D0AE-CB58-4F2F-B083-9451652536D6@edg.com> Message-ID: On 5 October 2016 at 15:32, David Vandevoorde wrote: > > On Oct 5, 2016, at 5:43 PM, Richard Smith > wrote: > > On 5 October 2016 at 11:54, Hubert Tong wrote: > >> In N4604 subclause 5.1.5 [expr.prim.lambda] paragraph 7, the conversion >> function to a pointer-to-function is constexpr. >> This means that the resulting pointer-to-function may be used as a >> template non-type argument and thus need a mangling. >> >> Clang currently mangles as a member of the closure type named __invoke, >> and GCC seems to use _FUN in place of __invoke. >> I find the Clang name to be less jarring. >> > I'd be fine with specifying either of these, or with some new custom > mangling. I note that EDG uses the _FUN mangling, like GCC, but unlike GCC > and Clang, does not make the name visible to class member name lookup. > > > Except in our GNU and Clang C++ modes, where we do make the name visible > ;-) (Our Clang-mode behavior is accidental in this regard, though.) > We at least have the decency to make __invoke a private member ;-) -------------- next part -------------- An HTML attachment was scrubbed... URL: From richardsmith at google.com Fri Oct 7 17:41:34 2016 From: richardsmith at google.com (Richard Smith) Date: Fri, 7 Oct 2016 10:41:34 -0700 Subject: [cxx-abi-dev] broken definition of "empty class" Message-ID: We define "empty class" as follows: "A class with no non-static data members other than zero-width bitfields, no virtual functions, no virtual base classes, and no non-empty non-virtual proper base classes." But this doesn't make sense: zero-width bitfields must be unnamed and unnamed bitfields are not members, so there is no such thing as a non-static data member that is a zero-width bitfield. (The same error exists in the definition of "nearly empty class".) There is implementation divergence on a case like this: struct A { int : 3; }; struct B : A { int n; }; This type has size 4 in Clang and size 8 in GCC; Clang takes the rule literally, and GCC applies a rule like: "A class with no non-static data members, no unnamed bitfields other than zero-width bitfields, no virtual functions, no virtual base classes, and no non-empty non-virtual proper base classes." As far as I can see, both behaviours are permitted by the C++ standard. I'm guessing that GCC's interpretation was the intended one? -------------- next part -------------- An HTML attachment was scrubbed... URL: From richardsmith at google.com Tue Oct 11 21:11:49 2016 From: richardsmith at google.com (Richard Smith) Date: Tue, 11 Oct 2016 14:11:49 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types Message-ID: Under http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html the noexceptness of a function type is now part of the type. As a result, we need manglings for exception-specifications on function pointer/reference types: void f(void()) {} void f(void() noexcept) {} // ok, overload not redefinition (It's not clear to me whether or not this was also necessary prior to C++17 to handle dependent exception specifications that appear lexically within the parameter list of a function template, and actual implementation practice varies as to whether such exception specifications are SFINAEable.) In order to handle overloading/SFINAE on exception specifications in dependent cases, we need to be able to mangle not only "noexcept", but also "noexcept(expression)" and "throw()". Suggestion for manglings: ::= nx -- non-throwing exception specification nX E -- computed (value-dependent) noexcept tw * E -- throw (types) ::= [] [] [Dx] F [Y] [] E In the case of throw(a, b, c), we could omit types that are neither instantiation-dependent nor pack expansions (if that omits all types, we can use the 'nx' mangling instead), since C++17 says you can't overload on the actual types in the dynamic exception specification, and we otherwise only need them to be present if they might result in a substitution failure. Thoughts? -------------- next part -------------- An HTML attachment was scrubbed... URL: From daveed at edg.com Tue Oct 11 22:07:27 2016 From: daveed at edg.com (David Vandevoorde) Date: Tue, 11 Oct 2016 18:07:27 -0400 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: References: Message-ID: > On Oct 11, 2016, at 5:11 PM, Richard Smith wrote: > > Under > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html > > the noexceptness of a function type is now part of the type. As a result, we need manglings for exception-specifications on function pointer/reference types: > > void f(void()) {} > void f(void() noexcept) {} // ok, overload not redefinition > > (It's not clear to me whether or not this was also necessary prior to C++17 to handle dependent exception specifications that appear lexically within the parameter list of a function template, and actual implementation practice varies as to whether such exception specifications are SFINAEable.) > > > In order to handle overloading/SFINAE on exception specifications in dependent cases, we need to be able to mangle not only "noexcept", but also "noexcept(expression)" and "throw()". Suggestion for manglings: > > ::= > nx -- non-throwing exception specification > nX E -- computed (value-dependent) noexcept > tw * E -- throw (types) > > ::= [] [] [Dx] F [Y] [] E > > In the case of throw(a, b, c), we could omit types that are neither instantiation-dependent nor pack expansions (if that omits all types, we can use the 'nx' mangling instead), since C++17 says you can't overload on the actual types in the dynamic exception specification, and we otherwise only need them to be present if they might result in a substitution failure. > > Thoughts? That seems reasonable to me. I don?t think we need to optimize the ?throw (a, b, c)? case: It?s deprecated anyway, and having all the types makes for nicer demangling. Daveed -------------- next part -------------- An HTML attachment was scrubbed... URL: From richardsmith at google.com Tue Oct 11 22:12:03 2016 From: richardsmith at google.com (Richard Smith) Date: Tue, 11 Oct 2016 15:12:03 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: References: Message-ID: On 11 October 2016 at 15:07, David Vandevoorde wrote: > > On Oct 11, 2016, at 5:11 PM, Richard Smith > wrote: > > Under > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html > > the noexceptness of a function type is now part of the type. As a result, > we need manglings for exception-specifications on function > pointer/reference types: > > void f(void()) {} > void f(void() noexcept) {} // ok, overload not redefinition > > (It's not clear to me whether or not this was also necessary prior to > C++17 to handle dependent exception specifications that appear lexically > within the parameter list of a function template, and actual implementation > practice varies as to whether such exception specifications are SFINAEable.) > > > In order to handle overloading/SFINAE on exception specifications in > dependent cases, we need to be able to mangle not only "noexcept", but also > "noexcept(expression)" and "throw()". Suggestion for manglings: > > ::= > nx -- non-throwing exception specification > nX E -- computed (value-dependent) noexcept > tw * E -- throw (types) > > ::= [] [] [Dx] F [Y] > [] E > > In the case of throw(a, b, c), we could omit types that are neither > instantiation-dependent nor pack expansions (if that omits all types, we > can use the 'nx' mangling instead), since C++17 says you can't overload on > the actual types in the dynamic exception specification, and we otherwise > only need them to be present if they might result in a substitution failure. > > Thoughts? > > > > That seems reasonable to me. I don?t think we need to optimize the ?throw > (a, b, c)? case: It?s deprecated anyway, and having all the types makes for > nicer demangling. > OK. As a special case, we do still need to mangle a non-dependent 'throw()' as nx rather than twE, since 'void () throw()' and 'void () noexcept' are the same type, but I think that falls out naturally if the nX and tw manglings are only used for dependent exception-specifications. -------------- next part -------------- An HTML attachment was scrubbed... URL: From rjmccall at apple.com Tue Oct 11 22:17:43 2016 From: rjmccall at apple.com (John McCall) Date: Tue, 11 Oct 2016 15:17:43 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: References: Message-ID: <594764E3-9635-4285-BED3-C19142345B44@apple.com> > On Oct 11, 2016, at 2:11 PM, Richard Smith wrote: > Under > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html > > the noexceptness of a function type is now part of the type. As a result, we need manglings for exception-specifications on function pointer/reference types: > > void f(void()) {} > void f(void() noexcept) {} // ok, overload not redefinition > > (It's not clear to me whether or not this was also necessary prior to C++17 to handle dependent exception specifications that appear lexically within the parameter list of a function template, and actual implementation practice varies as to whether such exception specifications are SFINAEable.) > > > In order to handle overloading/SFINAE on exception specifications in dependent cases, we need to be able to mangle not only "noexcept", but also "noexcept(expression)" and "throw()". Suggestion for manglings: > > ::= > nx -- non-throwing exception specification > nX E -- computed (value-dependent) noexcept > tw * E -- throw (types) > > ::= [] [] [Dx] F [Y] [] E > > In the case of throw(a, b, c), we could omit types that are neither instantiation-dependent nor pack expansions (if that omits all types, we can use the 'nx' mangling instead), since C++17 says you can't overload on the actual types in the dynamic exception specification, and we otherwise only need them to be present if they might result in a substitution failure. > > Thoughts? I think this is an amazingly late change to the language with pretty thin justification; does that count? This really is a major change which can reasonably be expected to cause substantial source and binary breakage. The proposal mentions transaction_safe as a feature that added similar complexity, but that analogy is weak because (1) TM is expected to be an optional TS, whereas noexcept is a mandatory core language feature, and (2) existing code does not use the transaction_safe attribute, whereas noexcept and throw() have seen widespread adoption, in the latter case for years. If it is a goal of this proposal to eliminate the underspecified fake type system around exception specifications, it is worth noting that it completely fails to do so, since the checking rules for direct function pointer assignments are still quite a bit stronger than those provided by the new type system. Furthermore, while the proposal does mention a fairly unlikely problem arising with template argument deduction, it fails to note the much larger one which is likely to break (or cause silently possible-miscompiles in) many metaprogramming systems where suddenly function types have acquire an entire new axis of differentiation. For example, this code only type-checks because of special rules allowing a conversion: template void take_fn(R (*fn)(A...)); ... extern void my_fn() noexcept; take_fn(my_fn); But, of course, a metaprogram inspecting a function type will completely fail to recognize a noexcept function type: template struct function_result { using type = R; }; And in fact, this adds yet another dimension to the combinatorial explosion of specializations required in order to match all function types: template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; template struct function_result { using type = R; }; You will note that I have omitted the necessary specializations for "transaction_safe", as well as the incredibly common extension of specialized calling conventions. This also breaks source compatibility for template matching, and basically every function template in the standard library is going to change manglings (and become *much* larger) due to noexcept expressions now being mangled. And the entire proposal seems to have forgotten about reference-to-function types. But if we're just talking about manglings, then yes, I think your ABI proposal is basically fine. :) It's a little unfortunate to include this kind of discrimination so early in the mangling, because some object/image file symbol tables optimize for symbols with common prefixes, but our mangling scheme is generally poor at achieving that anyway. John. -------------- next part -------------- An HTML attachment was scrubbed... URL: From richardsmith at google.com Tue Oct 11 23:20:31 2016 From: richardsmith at google.com (Richard Smith) Date: Tue, 11 Oct 2016 16:20:31 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: <594764E3-9635-4285-BED3-C19142345B44@apple.com> References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> Message-ID: On 11 October 2016 at 15:17, John McCall wrote: > On Oct 11, 2016, at 2:11 PM, Richard Smith > wrote: > Under > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html > > the noexceptness of a function type is now part of the type. As a result, > we need manglings for exception-specifications on function > pointer/reference types: > > void f(void()) {} > void f(void() noexcept) {} // ok, overload not redefinition > > (It's not clear to me whether or not this was also necessary prior to > C++17 to handle dependent exception specifications that appear lexically > within the parameter list of a function template, and actual implementation > practice varies as to whether such exception specifications are SFINAEable.) > > > In order to handle overloading/SFINAE on exception specifications in > dependent cases, we need to be able to mangle not only "noexcept", but also > "noexcept(expression)" and "throw()". Suggestion for manglings: > > ::= > nx -- non-throwing exception specification > nX E -- computed (value-dependent) noexcept > tw * E -- throw (types) > > ::= [] [] [Dx] F [Y] > [] E > > In the case of throw(a, b, c), we could omit types that are neither > instantiation-dependent nor pack expansions (if that omits all types, we > can use the 'nx' mangling instead), since C++17 says you can't overload on > the actual types in the dynamic exception specification, and we otherwise > only need them to be present if they might result in a substitution failure. > > Thoughts? > > > I think this is an amazingly late change to the language with pretty thin > justification; does that count? > > This really is a major change which can reasonably be expected to cause > substantial source and binary breakage. The proposal mentions > transaction_safe as a feature that added similar complexity, but that > analogy is weak because (1) TM is expected to be an optional TS, whereas > noexcept is a mandatory core language feature, and (2) existing code does > not use the transaction_safe attribute, whereas noexcept and throw() have > seen widespread adoption, in the latter case for years. > > If it is a goal of this proposal to eliminate the underspecified fake type > system around exception specifications, it is worth noting that it > completely fails to do so, since the checking rules for direct function > pointer assignments are still quite a bit stronger than those provided by > the new type system. > That was indeed a goal here. Can you expand on how it fails? Ignoring the (deprecated) dynamic exception specifications, this new approach seems stronger than the old type system, since it works for function types being arbitrarily nested within other types, not just one level deep within function types and pointers. Furthermore, while the proposal does mention a fairly unlikely problem > arising with template argument deduction, it fails to note the much larger > one which is likely to break (or cause silently possible-miscompiles in) > many metaprogramming systems where suddenly function types have acquire an > entire new axis of differentiation. For example, this code only > type-checks because of special rules allowing a conversion: > > template void take_fn(R (*fn)(A...)); > ... > extern void my_fn() noexcept; > take_fn(my_fn); > > But, of course, a metaprogram inspecting a function type will completely > fail to recognize a noexcept function type: > > template struct function_result { using > type = R; }; > > And in fact, this adds yet another dimension to the combinatorial > explosion of specializations required in order to match all function types: > > template struct function_result { using > type = R; }; > template struct function_result { > using type = R; }; > template struct function_result > { using type = R; }; > template struct function_result volatile> { using type = R; }; > template struct function_result { using > type = R; }; > template struct function_result { > using type = R; }; > template struct function_result &> { using type = R; }; > template struct function_result volatile &> { using type = R; }; > template struct function_result { > using type = R; }; > template struct function_result > { using type = R; }; > template struct function_result &&> { using type = R; }; > template struct function_result volatile &&> { using type = R; }; > template struct function_result > { using type = R; }; > template struct function_result const> { using type = R; }; > template struct function_result volatile> { using type = R; }; > template struct function_result const volatile> { using type = R; }; > template struct function_result &> { using type = R; }; > template struct function_result const &> { using type = R; }; > template struct function_result volatile &> { using type = R; }; > template struct function_result const volatile &> { using type = R; }; > template struct function_result &&> { using type = R; }; > template struct function_result const &&> { using type = R; }; > template struct function_result volatile &&> { using type = R; }; > template struct function_result const volatile &&> { using type = R; }; > Hmm, I thought we had added a rule to allow B to be deduced in template void f(R(A...) noexcept(B)); but it looks like we actually didn't. =( Yes, the above is a problem, if noexcept function types start to appear in existing code (for instance through use of decltype or by code that passes around noexcept function pointers). You will note that I have omitted the necessary specializations for > "transaction_safe", as well as the incredibly common extension of > specialized calling conventions. > > This also breaks source compatibility for template matching, and basically > every function template in the standard library is going to change > manglings (and become *much* larger) due to noexcept expressions now being > mangled. > It's a problem, but I don't think it's as bad as you claim. The mangling of a function still wouldn't include its exception specification; this would only affect mangling in cases where a parameter or return type or template argument involves a function type with an exception-specification -- a lot less common than every function template in the standard library, but this still does change manglings for existing code. > And the entire proposal seems to have forgotten about > reference-to-function types. > The change to [dcl.init.ref]p4 allows a reference to non-noexcept function to bind to a noexcept function, and this indirectly allows the same during overload resolution, casts, and so on. What additional considerations were missed? But if we're just talking about manglings, then yes, I think your ABI > proposal is basically fine. :) It's a little unfortunate to include this > kind of discrimination so early in the mangling, because some object/image > file symbol tables optimize for symbols with common prefixes, but our > mangling scheme is generally poor at achieving that anyway. > > John. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rjmccall at apple.com Wed Oct 12 02:20:03 2016 From: rjmccall at apple.com (John McCall) Date: Tue, 11 Oct 2016 19:20:03 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> Message-ID: <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> > On Oct 11, 2016, at 4:20 PM, Richard Smith wrote: > On 11 October 2016 at 15:17, John McCall > wrote: >> On Oct 11, 2016, at 2:11 PM, Richard Smith > wrote: >> Under >> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html >> >> the noexceptness of a function type is now part of the type. As a result, we need manglings for exception-specifications on function pointer/reference types: >> >> void f(void()) {} >> void f(void() noexcept) {} // ok, overload not redefinition >> >> (It's not clear to me whether or not this was also necessary prior to C++17 to handle dependent exception specifications that appear lexically within the parameter list of a function template, and actual implementation practice varies as to whether such exception specifications are SFINAEable.) >> >> >> In order to handle overloading/SFINAE on exception specifications in dependent cases, we need to be able to mangle not only "noexcept", but also "noexcept(expression)" and "throw()". Suggestion for manglings: >> >> ::= >> nx -- non-throwing exception specification >> nX E -- computed (value-dependent) noexcept >> tw * E -- throw (types) >> >> ::= [] [] [Dx] F [Y] [] E >> >> In the case of throw(a, b, c), we could omit types that are neither instantiation-dependent nor pack expansions (if that omits all types, we can use the 'nx' mangling instead), since C++17 says you can't overload on the actual types in the dynamic exception specification, and we otherwise only need them to be present if they might result in a substitution failure. >> >> Thoughts? > > I think this is an amazingly late change to the language with pretty thin justification; does that count? > > This really is a major change which can reasonably be expected to cause substantial source and binary breakage. The proposal mentions transaction_safe as a feature that added similar complexity, but that analogy is weak because (1) TM is expected to be an optional TS, whereas noexcept is a mandatory core language feature, and (2) existing code does not use the transaction_safe attribute, whereas noexcept and throw() have seen widespread adoption, in the latter case for years. > > If it is a goal of this proposal to eliminate the underspecified fake type system around exception specifications, it is worth noting that it completely fails to do so, since the checking rules for direct function pointer assignments are still quite a bit stronger than those provided by the new type system. > > That was indeed a goal here. Can you expand on how it fails? Ignoring the (deprecated) dynamic exception specifications, this new approach seems stronger than the old type system, since it works for function types being arbitrarily nested within other types, not just one level deep within function types and pointers. Are there any implementations which actually plan to throw out the dynamic exception specification matching logic? > Hmm, I thought we had added a rule to allow B to be deduced in > > template void f(R(A...) noexcept(B)); > > but it looks like we actually didn't. =( Hmm, that would work pretty well for this case. > Yes, the above is a problem, if noexcept function types start to appear in existing code (for instance through use of decltype or by code that passes around noexcept function pointers). Well, recall that noexcept function types have always been writable; they just didn't necessarily get enforced reliably. Also, noexcept and throw() are pretty popular, and aren't there proposals to infer them in more cases? It's really hard to say abstractly how much impact this will have. There's a lot of potential for breakage, but it's also quite possible that there won't be many changes and that almost all of them will be lost in the great grey expanse of C++ binary compatibility. > You will note that I have omitted the necessary specializations for "transaction_safe", as well as the incredibly common extension of specialized calling conventions. > > This also breaks source compatibility for template matching, and basically every function template in the standard library is going to change manglings (and become *much* larger) due to noexcept expressions now being mangled. > > It's a problem, but I don't think it's as bad as you claim. The mangling of a function still wouldn't include its exception specification; this would only affect mangling in cases where a parameter or return type or template argument involves a function type with an exception-specification -- a lot less common than every function template in the standard library, but this still does change manglings for existing code. Okay, so it only triggers SFINAE failures in nested function types, and you can't overload templates by it? I agree that that helps a lot. > And the entire proposal seems to have forgotten about reference-to-function types. > > The change to [dcl.init.ref]p4 allows a reference to non-noexcept function to bind to a noexcept function, and this indirectly allows the same during overload resolution, casts, and so on. What additional considerations were missed? I hadn't realized that the expression logic was so consistent about defining e.g. the behavior of the conditional operator on l-values in terms of reference binding. I apologize. ...I see that this adds a new special case to exception handling. John. > But if we're just talking about manglings, then yes, I think your ABI proposal is basically fine. :) It's a little unfortunate to include this kind of discrimination so early in the mangling, because some object/image file symbol tables optimize for symbols with common prefixes, but our mangling scheme is generally poor at achieving that anyway. > > John. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rjmccall at apple.com Wed Oct 12 02:22:42 2016 From: rjmccall at apple.com (John McCall) Date: Tue, 11 Oct 2016 19:22:42 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> Message-ID: <67770DEE-E54B-4E7C-AB42-574B50FCD2E4@apple.com> > On Oct 11, 2016, at 4:20 PM, Richard Smith > wrote: > On 11 October 2016 at 15:17, John McCall > wrote: >> On Oct 11, 2016, at 2:11 PM, Richard Smith > wrote: >> Under >> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html >> >> the noexceptness of a function type is now part of the type. As a result, we need manglings for exception-specifications on function pointer/reference types: >> >> void f(void()) {} >> void f(void() noexcept) {} // ok, overload not redefinition >> >> (It's not clear to me whether or not this was also necessary prior to C++17 to handle dependent exception specifications that appear lexically within the parameter list of a function template, and actual implementation practice varies as to whether such exception specifications are SFINAEable.) >> >> >> In order to handle overloading/SFINAE on exception specifications in dependent cases, we need to be able to mangle not only "noexcept", but also "noexcept(expression)" and "throw()". Suggestion for manglings: >> >> ::= >> nx -- non-throwing exception specification >> nX E -- computed (value-dependent) noexcept >> tw * E -- throw (types) >> >> ::= [] [] [Dx] F [Y] [] E >> >> In the case of throw(a, b, c), we could omit types that are neither instantiation-dependent nor pack expansions (if that omits all types, we can use the 'nx' mangling instead), since C++17 says you can't overload on the actual types in the dynamic exception specification, and we otherwise only need them to be present if they might result in a substitution failure. >> >> Thoughts? > > I think this is an amazingly late change to the language with pretty thin justification; does that count? > > This really is a major change which can reasonably be expected to cause substantial source and binary breakage. The proposal mentions transaction_safe as a feature that added similar complexity, but that analogy is weak because (1) TM is expected to be an optional TS, whereas noexcept is a mandatory core language feature, and (2) existing code does not use the transaction_safe attribute, whereas noexcept and throw() have seen widespread adoption, in the latter case for years. > > If it is a goal of this proposal to eliminate the underspecified fake type system around exception specifications, it is worth noting that it completely fails to do so, since the checking rules for direct function pointer assignments are still quite a bit stronger than those provided by the new type system. > > That was indeed a goal here. Can you expand on how it fails? Ignoring the (deprecated) dynamic exception specifications, this new approach seems stronger than the old type system, since it works for function types being arbitrarily nested within other types, not just one level deep within function types and pointers. Are there any implementations which actually plan to throw out the dynamic exception specification matching logic? > Hmm, I thought we had added a rule to allow B to be deduced in > > template void f(R(A...) noexcept(B)); > > but it looks like we actually didn't. =( Hmm, that would work pretty well for this case. > Yes, the above is a problem, if noexcept function types start to appear in existing code (for instance through use of decltype or by code that passes around noexcept function pointers). Well, recall that noexcept function types have always been writable; they just didn't necessarily get enforced reliably. Also, noexcept and throw() are pretty popular, and aren't there proposals to infer them in more cases? It's really hard to say abstractly how much impact this will have. There's a lot of potential for breakage, but it's also quite possible that there won't be many changes and that almost all of them will be lost in the great grey expanse of C++ binary compatibility. > You will note that I have omitted the necessary specializations for "transaction_safe", as well as the incredibly common extension of specialized calling conventions. > > This also breaks source compatibility for template matching, and basically every function template in the standard library is going to change manglings (and become *much* larger) due to noexcept expressions now being mangled. > > It's a problem, but I don't think it's as bad as you claim. The mangling of a function still wouldn't include its exception specification; this would only affect mangling in cases where a parameter or return type or template argument involves a function type with an exception-specification -- a lot less common than every function template in the standard library, but this still does change manglings for existing code. Okay, so it only triggers SFINAE failures in nested function types, and you can't overload templates by it? I agree that that helps a lot. > And the entire proposal seems to have forgotten about reference-to-function types. > > The change to [dcl.init.ref]p4 allows a reference to non-noexcept function to bind to a noexcept function, and this indirectly allows the same during overload resolution, casts, and so on. What additional considerations were missed? I hadn't realized that the expression logic was so consistent about defining e.g. the behavior of the conditional operator on l-values in terms of reference binding. I apologize. ...I see that this adds a new special case to exception handling. John. > But if we're just talking about manglings, then yes, I think your ABI proposal is basically fine. :) It's a little unfortunate to include this kind of discrimination so early in the mangling, because some object/image file symbol tables optimize for symbols with common prefixes, but our mangling scheme is generally poor at achieving that anyway. > > John. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From richardsmith at google.com Wed Oct 12 18:58:14 2016 From: richardsmith at google.com (Richard Smith) Date: Wed, 12 Oct 2016 11:58:14 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> Message-ID: On 11 October 2016 at 19:20, John McCall wrote: > On Oct 11, 2016, at 4:20 PM, Richard Smith > wrote: > On 11 October 2016 at 15:17, John McCall wrote: > >> On Oct 11, 2016, at 2:11 PM, Richard Smith >> wrote: >> Under >> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html >> >> the noexceptness of a function type is now part of the type. As a result, >> we need manglings for exception-specifications on function >> pointer/reference types: >> >> void f(void()) {} >> void f(void() noexcept) {} // ok, overload not redefinition >> >> (It's not clear to me whether or not this was also necessary prior to >> C++17 to handle dependent exception specifications that appear lexically >> within the parameter list of a function template, and actual implementation >> practice varies as to whether such exception specifications are SFINAEable.) >> >> >> In order to handle overloading/SFINAE on exception specifications in >> dependent cases, we need to be able to mangle not only "noexcept", but also >> "noexcept(expression)" and "throw()". Suggestion for manglings: >> >> ::= >> nx -- non-throwing exception specification >> nX E -- computed (value-dependent) noexcept >> tw * E -- throw (types) >> >> ::= [] [] [Dx] F [Y] >> [] E >> >> In the case of throw(a, b, c), we could omit types that are neither >> instantiation-dependent nor pack expansions (if that omits all types, we >> can use the 'nx' mangling instead), since C++17 says you can't overload on >> the actual types in the dynamic exception specification, and we otherwise >> only need them to be present if they might result in a substitution failure. >> >> Thoughts? >> >> >> I think this is an amazingly late change to the language with pretty thin >> justification; does that count? >> >> This really is a major change which can reasonably be expected to cause >> substantial source and binary breakage. The proposal mentions >> transaction_safe as a feature that added similar complexity, but that >> analogy is weak because (1) TM is expected to be an optional TS, whereas >> noexcept is a mandatory core language feature, and (2) existing code does >> not use the transaction_safe attribute, whereas noexcept and throw() have >> seen widespread adoption, in the latter case for years. >> >> If it is a goal of this proposal to eliminate the underspecified fake >> type system around exception specifications, it is worth noting that it >> completely fails to do so, since the checking rules for direct function >> pointer assignments are still quite a bit stronger than those provided by >> the new type system. >> > > That was indeed a goal here. Can you expand on how it fails? Ignoring the > (deprecated) dynamic exception specifications, this new approach seems > stronger than the old type system, since it works for function types being > arbitrarily nested within other types, not just one level deep within > function types and pointers. > > > Are there any implementations which actually plan to throw out the dynamic > exception specification matching logic? > *shrug* Maybe MSVC? Any conforming C++17 implementation will need to demote that side of their enforcement to a warning. And I think there are NB comments for C++17 proposing that we apply http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0003r4.html for C++17 rather than waiting for C++20. > Hmm, I thought we had added a rule to allow B to be deduced in > > template void f(R(A...) noexcept(B)); > > but it looks like we actually didn't. =( > > > Hmm, that would work pretty well for this case. > > Yes, the above is a problem, if noexcept function types start to appear in > existing code (for instance through use of decltype or by code that passes > around noexcept function pointers). > > > Well, recall that noexcept function types have always been writable; they > just didn't necessarily get enforced reliably. Also, noexcept and throw() > are pretty popular, and aren't there proposals to infer them in more cases? > Proposals, yes, but nothing in C++17. > It's really hard to say abstractly how much impact this will have. > There's a lot of potential for breakage, but it's also quite possible that > there won't be many changes and that almost all of them will be lost in the > great grey expanse of C++ binary compatibility. > We'll have an implementation soon, and then we can find out whether this is a problem in practice. > You will note that I have omitted the necessary specializations for >> "transaction_safe", as well as the incredibly common extension of >> specialized calling conventions. >> >> This also breaks source compatibility for template matching, and >> basically every function template in the standard library is going to >> change manglings (and become *much* larger) due to noexcept expressions now >> being mangled. >> > > It's a problem, but I don't think it's as bad as you claim. The mangling > of a function still wouldn't include its exception specification; this > would only affect mangling in cases where a parameter or return type or > template argument involves a function type with an exception-specification > -- a lot less common than every function template in the standard library, > but this still does change manglings for existing code. > > > Okay, so it only triggers SFINAE failures in nested function types, and > you can't overload templates by it? I agree that that helps a lot. > > And the entire proposal seems to have forgotten about >> reference-to-function types. >> > > The change to [dcl.init.ref]p4 allows a reference to non-noexcept function > to bind to a noexcept function, and this indirectly allows the same during > overload resolution, casts, and so on. What additional considerations were > missed? > > > I hadn't realized that the expression logic was so consistent about > defining e.g. the behavior of the conditional operator on l-values in terms > of reference binding. I apologize. > > ...I see that this adds a new special case to exception handling. > Yes; I'd forgotten to mention this side of the ABI change. We'll also need a new flag on type_info objects to model this. In line with the transaction_safe changes that Jason proposed, I suggest adding a __noexcept_mask = 0x40 to __pbase_type_info, and representing a pointer to noexcept function as a pointer with __noexcept_mask bit set to the corresponding *non-noexcept* function pointer type. John. > > But if we're just talking about manglings, then yes, I think your ABI >> proposal is basically fine. :) It's a little unfortunate to include this >> kind of discrimination so early in the mangling, because some object/image >> file symbol tables optimize for symbols with common prefixes, but our >> mangling scheme is generally poor at achieving that anyway. >> >> John. >> > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rjmccall at apple.com Wed Oct 12 20:51:12 2016 From: rjmccall at apple.com (John McCall) Date: Wed, 12 Oct 2016 13:51:12 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> Message-ID: <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> > On Oct 12, 2016, at 11:58 AM, Richard Smith wrote: > On 11 October 2016 at 19:20, John McCall > wrote: >> On Oct 11, 2016, at 4:20 PM, Richard Smith > wrote: >> On 11 October 2016 at 15:17, John McCall > wrote: >>> On Oct 11, 2016, at 2:11 PM, Richard Smith > wrote: >>> Under >>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html >>> >>> the noexceptness of a function type is now part of the type. As a result, we need manglings for exception-specifications on function pointer/reference types: >>> >>> void f(void()) {} >>> void f(void() noexcept) {} // ok, overload not redefinition >>> >>> (It's not clear to me whether or not this was also necessary prior to C++17 to handle dependent exception specifications that appear lexically within the parameter list of a function template, and actual implementation practice varies as to whether such exception specifications are SFINAEable.) >>> >>> >>> In order to handle overloading/SFINAE on exception specifications in dependent cases, we need to be able to mangle not only "noexcept", but also "noexcept(expression)" and "throw()". Suggestion for manglings: >>> >>> ::= >>> nx -- non-throwing exception specification >>> nX E -- computed (value-dependent) noexcept >>> tw * E -- throw (types) >>> >>> ::= [] [] [Dx] F [Y] [] E >>> >>> In the case of throw(a, b, c), we could omit types that are neither instantiation-dependent nor pack expansions (if that omits all types, we can use the 'nx' mangling instead), since C++17 says you can't overload on the actual types in the dynamic exception specification, and we otherwise only need them to be present if they might result in a substitution failure. >>> >>> Thoughts? >> >> I think this is an amazingly late change to the language with pretty thin justification; does that count? >> >> This really is a major change which can reasonably be expected to cause substantial source and binary breakage. The proposal mentions transaction_safe as a feature that added similar complexity, but that analogy is weak because (1) TM is expected to be an optional TS, whereas noexcept is a mandatory core language feature, and (2) existing code does not use the transaction_safe attribute, whereas noexcept and throw() have seen widespread adoption, in the latter case for years. >> >> If it is a goal of this proposal to eliminate the underspecified fake type system around exception specifications, it is worth noting that it completely fails to do so, since the checking rules for direct function pointer assignments are still quite a bit stronger than those provided by the new type system. >> >> That was indeed a goal here. Can you expand on how it fails? Ignoring the (deprecated) dynamic exception specifications, this new approach seems stronger than the old type system, since it works for function types being arbitrarily nested within other types, not just one level deep within function types and pointers. > > Are there any implementations which actually plan to throw out the dynamic exception specification matching logic? > > *shrug* Maybe MSVC? Any conforming C++17 implementation will need to demote that side of their enforcement to a warning. And I think there are NB comments for C++17 proposing that we apply http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0003r4.html for C++17 rather than waiting for C++20. Not enforcing the old rules is also compatibility-breaking, of course, because of SFINAE. >> Hmm, I thought we had added a rule to allow B to be deduced in >> >> template void f(R(A...) noexcept(B)); >> >> but it looks like we actually didn't. =( > > Hmm, that would work pretty well for this case. > >> Yes, the above is a problem, if noexcept function types start to appear in existing code (for instance through use of decltype or by code that passes around noexcept function pointers). > > Well, recall that noexcept function types have always been writable; they just didn't necessarily get enforced reliably. Also, noexcept and throw() are pretty popular, and aren't there proposals to infer them in more cases? > > Proposals, yes, but nothing in C++17. I think it's reasonable to anticipate that when judging how often functions will be noexcept. > It's really hard to say abstractly how much impact this will have. There's a lot of potential for breakage, but it's also quite possible that there won't be many changes and that almost all of them will be lost in the great grey expanse of C++ binary compatibility. > > We'll have an implementation soon, and then we can find out whether this is a problem in practice. I'll admit that I don't attend committee meetings, but I thought that implementation experience was expected *prior* to standardization, not something that gets done months after voting the thing in concurrently with the committee finalizing the language in a draft for next year's release. >> You will note that I have omitted the necessary specializations for "transaction_safe", as well as the incredibly common extension of specialized calling conventions. >> >> This also breaks source compatibility for template matching, and basically every function template in the standard library is going to change manglings (and become *much* larger) due to noexcept expressions now being mangled. >> >> It's a problem, but I don't think it's as bad as you claim. The mangling of a function still wouldn't include its exception specification; this would only affect mangling in cases where a parameter or return type or template argument involves a function type with an exception-specification -- a lot less common than every function template in the standard library, but this still does change manglings for existing code. > > Okay, so it only triggers SFINAE failures in nested function types, and you can't overload templates by it? I agree that that helps a lot. >> And the entire proposal seems to have forgotten about reference-to-function types. >> >> The change to [dcl.init.ref]p4 allows a reference to non-noexcept function to bind to a noexcept function, and this indirectly allows the same during overload resolution, casts, and so on. What additional considerations were missed? > > I hadn't realized that the expression logic was so consistent about defining e.g. the behavior of the conditional operator on l-values in terms of reference binding. I apologize. > > ...I see that this adds a new special case to exception handling. > > Yes; I'd forgotten to mention this side of the ABI change. > > We'll also need a new flag on type_info objects to model this. In line with the transaction_safe changes that Jason proposed, I suggest adding a __noexcept_mask = 0x40 to __pbase_type_info, and representing a pointer to noexcept function as a pointer with __noexcept_mask bit set to the corresponding *non-noexcept* function pointer type. I strongly disagree; we should take this opportunity to revisit that decision. The floodgates are open, and this set of function type attributes is clearly going to grow over time. (It's actually transaction_safe that really drives this point home; noexcept is at least a longstanding part of the core language in various forms.) We also have a lot of vendor-specific function type attributes that are part of the type but just aren't standardized and can't be represented in type_info. I don't think it makes sense to indefinitely keep hacking these things into the pointer type flags; we should just bite the bullet and create a new function_type_info subclass. John. -------------- next part -------------- An HTML attachment was scrubbed... URL: From richardsmith at google.com Wed Oct 12 21:09:02 2016 From: richardsmith at google.com (Richard Smith) Date: Wed, 12 Oct 2016 14:09:02 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> Message-ID: On 12 October 2016 at 13:51, John McCall wrote: > On Oct 12, 2016, at 11:58 AM, Richard Smith > wrote: > On 11 October 2016 at 19:20, John McCall wrote: > >> On Oct 11, 2016, at 4:20 PM, Richard Smith >> wrote: >> On 11 October 2016 at 15:17, John McCall wrote: >> >>> On Oct 11, 2016, at 2:11 PM, Richard Smith >>> wrote: >>> Under >>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html >>> >>> the noexceptness of a function type is now part of the type. As a >>> result, we need manglings for exception-specifications on function >>> pointer/reference types: >>> >>> void f(void()) {} >>> void f(void() noexcept) {} // ok, overload not redefinition >>> >>> (It's not clear to me whether or not this was also necessary prior to >>> C++17 to handle dependent exception specifications that appear lexically >>> within the parameter list of a function template, and actual implementation >>> practice varies as to whether such exception specifications are SFINAEable.) >>> >>> >>> In order to handle overloading/SFINAE on exception specifications in >>> dependent cases, we need to be able to mangle not only "noexcept", but also >>> "noexcept(expression)" and "throw()". Suggestion for manglings: >>> >>> ::= >>> nx -- non-throwing exception specification >>> nX E -- computed (value-dependent) noexcept >>> tw * E -- throw (types) >>> >>> ::= [] [] [Dx] F [Y] >>> [] E >>> >>> In the case of throw(a, b, c), we could omit types that are neither >>> instantiation-dependent nor pack expansions (if that omits all types, we >>> can use the 'nx' mangling instead), since C++17 says you can't overload on >>> the actual types in the dynamic exception specification, and we otherwise >>> only need them to be present if they might result in a substitution failure. >>> >>> Thoughts? >>> >>> >>> I think this is an amazingly late change to the language with pretty >>> thin justification; does that count? >>> >>> This really is a major change which can reasonably be expected to cause >>> substantial source and binary breakage. The proposal mentions >>> transaction_safe as a feature that added similar complexity, but that >>> analogy is weak because (1) TM is expected to be an optional TS, whereas >>> noexcept is a mandatory core language feature, and (2) existing code does >>> not use the transaction_safe attribute, whereas noexcept and throw() have >>> seen widespread adoption, in the latter case for years. >>> >>> If it is a goal of this proposal to eliminate the underspecified fake >>> type system around exception specifications, it is worth noting that it >>> completely fails to do so, since the checking rules for direct function >>> pointer assignments are still quite a bit stronger than those provided by >>> the new type system. >>> >> >> That was indeed a goal here. Can you expand on how it fails? Ignoring the >> (deprecated) dynamic exception specifications, this new approach seems >> stronger than the old type system, since it works for function types being >> arbitrarily nested within other types, not just one level deep within >> function types and pointers. >> >> >> Are there any implementations which actually plan to throw out the >> dynamic exception specification matching logic? >> > > *shrug* Maybe MSVC? Any conforming C++17 implementation will need to > demote that side of their enforcement to a warning. And I think there are > NB comments for C++17 proposing that we apply http://www.open-std.org/ > jtc1/sc22/wg21/docs/papers/2016/p0003r4.html for C++17 rather than > waiting for C++20. > > > Not enforcing the old rules is also compatibility-breaking, of course, > because of SFINAE. > > Hmm, I thought we had added a rule to allow B to be deduced in >> >> template void f(R(A...) noexcept(B)); >> >> but it looks like we actually didn't. =( >> >> >> Hmm, that would work pretty well for this case. >> >> Yes, the above is a problem, if noexcept function types start to appear >> in existing code (for instance through use of decltype or by code that >> passes around noexcept function pointers). >> >> >> Well, recall that noexcept function types have always been writable; they >> just didn't necessarily get enforced reliably. Also, noexcept and throw() >> are pretty popular, and aren't there proposals to infer them in more cases? >> > > Proposals, yes, but nothing in C++17. > > > I think it's reasonable to anticipate that when judging how often > functions will be noexcept. > > > It's really hard to say abstractly how much impact this will have. >> There's a lot of potential for breakage, but it's also quite possible that >> there won't be many changes and that almost all of them will be lost in the >> great grey expanse of C++ binary compatibility. >> > > We'll have an implementation soon, and then we can find out whether this > is a problem in practice. > > > I'll admit that I don't attend committee meetings, but I thought that > implementation experience was expected *prior* to standardization, not > something that gets done months after voting the thing in concurrently with > the committee finalizing the language in a draft for next year's release. > Some of us try to push for that. So far we've not had much success. > You will note that I have omitted the necessary specializations for >>> "transaction_safe", as well as the incredibly common extension of >>> specialized calling conventions. >>> >>> This also breaks source compatibility for template matching, and >>> basically every function template in the standard library is going to >>> change manglings (and become *much* larger) due to noexcept expressions now >>> being mangled. >>> >> >> It's a problem, but I don't think it's as bad as you claim. The mangling >> of a function still wouldn't include its exception specification; this >> would only affect mangling in cases where a parameter or return type or >> template argument involves a function type with an exception-specification >> -- a lot less common than every function template in the standard library, >> but this still does change manglings for existing code. >> >> >> Okay, so it only triggers SFINAE failures in nested function types, and >> you can't overload templates by it? I agree that that helps a lot. >> >> And the entire proposal seems to have forgotten about >>> reference-to-function types. >>> >> >> The change to [dcl.init.ref]p4 allows a reference to non-noexcept >> function to bind to a noexcept function, and this indirectly allows the >> same during overload resolution, casts, and so on. What additional >> considerations were missed? >> >> >> I hadn't realized that the expression logic was so consistent about >> defining e.g. the behavior of the conditional operator on l-values in terms >> of reference binding. I apologize. >> >> ...I see that this adds a new special case to exception handling. >> > > Yes; I'd forgotten to mention this side of the ABI change. > > We'll also need a new flag on type_info objects to model this. In line > with the transaction_safe changes that Jason proposed, I suggest adding a > __noexcept_mask = 0x40 to __pbase_type_info, and representing a pointer to > noexcept function as a pointer with __noexcept_mask bit set to the > corresponding *non-noexcept* function pointer type. > > > I strongly disagree; we should take this opportunity to revisit that > decision. The floodgates are open, and this set of function type > attributes is clearly going to grow over time. (It's actually > transaction_safe that really drives this point home; noexcept is at least a > longstanding part of the core language in various forms.) We also have a > lot of vendor-specific function type attributes that are part of the type > but just aren't standardized and can't be represented in type_info. I > don't think it makes sense to indefinitely keep hacking these things into > the pointer type flags; we should just bite the bullet and create a new > function_type_info subclass. > OK. How about this: class __qualified_function_type_info : public __function_type_info { public: const __function_type_info *__base_type; unsigned int __qualifiers; enum __qualifiers_mask { __const_mask = 0x01, __volatile_mask = 0x02, __restrict_mask = 0x04, __lval_ref_mask = 0x08, __rval_ref_mask = 0x10, __noexcept_mask = 0x20, __transaction_safe_mask = 0x40 }; }; ... where __base_type is the unqualified function type, included to avoid the need for string comparisons when checking for a matching exception handler. The base class __function_type_info would be used for types with no qualifiers. It might also be reasonable to reserve a bit for 'noreturn', since several compilers treat it as part of the function type in some way. -------------- next part -------------- An HTML attachment was scrubbed... URL: From daveed at edg.com Wed Oct 12 21:35:39 2016 From: daveed at edg.com (David Vandevoorde) Date: Wed, 12 Oct 2016 17:35:39 -0400 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> Message-ID: <5A4BB685-5D8A-4179-89E5-A565B8184359@edg.com> > On Oct 12, 2016, at 4:51 PM, John McCall wrote: [?] > I'll admit that I don't attend committee meetings, but I thought that implementation experience was expected *prior* to standardization, not something that gets done months after voting the thing in concurrently with the committee finalizing the language in a draft for next year's release. That?s cute ;-) > >>> You will note that I have omitted the necessary specializations for "transaction_safe", as well as the incredibly common extension of specialized calling conventions. >>> >>> This also breaks source compatibility for template matching, and basically every function template in the standard library is going to change manglings (and become *much* larger) due to noexcept expressions now being mangled. >>> >>> It's a problem, but I don't think it's as bad as you claim. The mangling of a function still wouldn't include its exception specification; this would only affect mangling in cases where a parameter or return type or template argument involves a function type with an exception-specification -- a lot less common than every function template in the standard library, but this still does change manglings for existing code. >> >> Okay, so it only triggers SFINAE failures in nested function types, and you can't overload templates by it? I agree that that helps a lot. >>> And the entire proposal seems to have forgotten about reference-to-function types. >>> >>> The change to [dcl.init.ref]p4 allows a reference to non-noexcept function to bind to a noexcept function, and this indirectly allows the same during overload resolution, casts, and so on. What additional considerations were missed? >> >> I hadn't realized that the expression logic was so consistent about defining e.g. the behavior of the conditional operator on l-values in terms of reference binding. I apologize. >> >> ...I see that this adds a new special case to exception handling. >> >> Yes; I'd forgotten to mention this side of the ABI change. >> >> We'll also need a new flag on type_info objects to model this. In line with the transaction_safe changes that Jason proposed, I suggest adding a __noexcept_mask = 0x40 to __pbase_type_info, and representing a pointer to noexcept function as a pointer with __noexcept_mask bit set to the corresponding *non-noexcept* function pointer type. > > I strongly disagree; we should take this opportunity to revisit that decision. The floodgates are open, and this set of function type attributes is clearly going to grow over time. (It's actually transaction_safe that really drives this point home; noexcept is at least a longstanding part of the core language in various forms.) We also have a lot of vendor-specific function type attributes that are part of the type but just aren't standardized and can't be represented in type_info. I don't think it makes sense to indefinitely keep hacking these things into the pointer type flags; we should just bite the bullet and create a new function_type_info subclass. I agree with you (John). (That said, I?ll keep resisting adding standard bifurcations to function types. ?contracts? and one alternative for coroutines are currently trying to add to that list.) Daveed -------------- next part -------------- An HTML attachment was scrubbed... URL: From jhs at edg.com Wed Oct 12 21:29:04 2016 From: jhs at edg.com (John Spicer) Date: Wed, 12 Oct 2016 17:29:04 -0400 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> Message-ID: <08E9A3AC-30B3-4DB3-920C-4ADBDFCC455D@edg.com> > On Oct 12, 2016, at 4:51 PM, John McCall wrote: >> > > > I'll admit that I don't attend committee meetings, but I thought that implementation experience was expected *prior* to standardization, not something that gets done months after voting the thing in concurrently with the committee finalizing the language in a draft for next year's release. > Where on earth in the history of the C++ committee would you have gotten that impression :-( John. From rjmccall at apple.com Wed Oct 12 23:00:58 2016 From: rjmccall at apple.com (John McCall) Date: Wed, 12 Oct 2016 16:00:58 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: <08E9A3AC-30B3-4DB3-920C-4ADBDFCC455D@edg.com> References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> <08E9A3AC-30B3-4DB3-920C-4ADBDFCC455D@edg.com> Message-ID: > On Oct 12, 2016, at 2:29 PM, John Spicer wrote: >> On Oct 12, 2016, at 4:51 PM, John McCall wrote: >> I'll admit that I don't attend committee meetings, but I thought that implementation experience was expected *prior* to standardization, not something that gets done months after voting the thing in concurrently with the committee finalizing the language in a draft for next year's release. > > Where on earth in the history of the C++ committee would you have gotten that impression :-( :( John From rjmccall at apple.com Wed Oct 12 23:34:15 2016 From: rjmccall at apple.com (John McCall) Date: Wed, 12 Oct 2016 16:34:15 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> Message-ID: <52713467-E6E0-4B91-8F79-EB5D34E905AD@apple.com> > On Oct 12, 2016, at 2:09 PM, Richard Smith wrote: > > On 12 October 2016 at 13:51, John McCall > wrote: >> On Oct 12, 2016, at 11:58 AM, Richard Smith > wrote: >> On 11 October 2016 at 19:20, John McCall > wrote: >>> On Oct 11, 2016, at 4:20 PM, Richard Smith > wrote: >>> On 11 October 2016 at 15:17, John McCall > wrote: >>>> On Oct 11, 2016, at 2:11 PM, Richard Smith > wrote: >>>> Under >>>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html >>>> >>>> the noexceptness of a function type is now part of the type. As a result, we need manglings for exception-specifications on function pointer/reference types: >>>> >>>> void f(void()) {} >>>> void f(void() noexcept) {} // ok, overload not redefinition >>>> >>>> (It's not clear to me whether or not this was also necessary prior to C++17 to handle dependent exception specifications that appear lexically within the parameter list of a function template, and actual implementation practice varies as to whether such exception specifications are SFINAEable.) >>>> >>>> >>>> In order to handle overloading/SFINAE on exception specifications in dependent cases, we need to be able to mangle not only "noexcept", but also "noexcept(expression)" and "throw()". Suggestion for manglings: >>>> >>>> ::= >>>> nx -- non-throwing exception specification >>>> nX E -- computed (value-dependent) noexcept >>>> tw * E -- throw (types) >>>> >>>> ::= [] [] [Dx] F [Y] [] E >>>> >>>> In the case of throw(a, b, c), we could omit types that are neither instantiation-dependent nor pack expansions (if that omits all types, we can use the 'nx' mangling instead), since C++17 says you can't overload on the actual types in the dynamic exception specification, and we otherwise only need them to be present if they might result in a substitution failure. >>>> >>>> Thoughts? >>> >>> I think this is an amazingly late change to the language with pretty thin justification; does that count? >>> >>> This really is a major change which can reasonably be expected to cause substantial source and binary breakage. The proposal mentions transaction_safe as a feature that added similar complexity, but that analogy is weak because (1) TM is expected to be an optional TS, whereas noexcept is a mandatory core language feature, and (2) existing code does not use the transaction_safe attribute, whereas noexcept and throw() have seen widespread adoption, in the latter case for years. >>> >>> If it is a goal of this proposal to eliminate the underspecified fake type system around exception specifications, it is worth noting that it completely fails to do so, since the checking rules for direct function pointer assignments are still quite a bit stronger than those provided by the new type system. >>> >>> That was indeed a goal here. Can you expand on how it fails? Ignoring the (deprecated) dynamic exception specifications, this new approach seems stronger than the old type system, since it works for function types being arbitrarily nested within other types, not just one level deep within function types and pointers. >> >> Are there any implementations which actually plan to throw out the dynamic exception specification matching logic? >> >> *shrug* Maybe MSVC? Any conforming C++17 implementation will need to demote that side of their enforcement to a warning. And I think there are NB comments for C++17 proposing that we apply http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0003r4.html for C++17 rather than waiting for C++20. > > Not enforcing the old rules is also compatibility-breaking, of course, because of SFINAE. > >>> Hmm, I thought we had added a rule to allow B to be deduced in >>> >>> template void f(R(A...) noexcept(B)); >>> >>> but it looks like we actually didn't. =( >> >> Hmm, that would work pretty well for this case. >> >>> Yes, the above is a problem, if noexcept function types start to appear in existing code (for instance through use of decltype or by code that passes around noexcept function pointers). >> >> Well, recall that noexcept function types have always been writable; they just didn't necessarily get enforced reliably. Also, noexcept and throw() are pretty popular, and aren't there proposals to infer them in more cases? >> >> Proposals, yes, but nothing in C++17. > > I think it's reasonable to anticipate that when judging how often functions will be noexcept. > >> It's really hard to say abstractly how much impact this will have. There's a lot of potential for breakage, but it's also quite possible that there won't be many changes and that almost all of them will be lost in the great grey expanse of C++ binary compatibility. >> >> We'll have an implementation soon, and then we can find out whether this is a problem in practice. > > I'll admit that I don't attend committee meetings, but I thought that implementation experience was expected *prior* to standardization, not something that gets done months after voting the thing in concurrently with the committee finalizing the language in a draft for next year's release. > > Some of us try to push for that. So far we've not had much success. A pity. Okay. Doug Gregor has strong opinions about this, but I'll let him speak for himself if he wants; I'll drop my own objections to the feature pending implementation experience. >>> You will note that I have omitted the necessary specializations for "transaction_safe", as well as the incredibly common extension of specialized calling conventions. >>> >>> This also breaks source compatibility for template matching, and basically every function template in the standard library is going to change manglings (and become *much* larger) due to noexcept expressions now being mangled. >>> >>> It's a problem, but I don't think it's as bad as you claim. The mangling of a function still wouldn't include its exception specification; this would only affect mangling in cases where a parameter or return type or template argument involves a function type with an exception-specification -- a lot less common than every function template in the standard library, but this still does change manglings for existing code. >> >> Okay, so it only triggers SFINAE failures in nested function types, and you can't overload templates by it? I agree that that helps a lot. >>> And the entire proposal seems to have forgotten about reference-to-function types. >>> >>> The change to [dcl.init.ref]p4 allows a reference to non-noexcept function to bind to a noexcept function, and this indirectly allows the same during overload resolution, casts, and so on. What additional considerations were missed? >> >> I hadn't realized that the expression logic was so consistent about defining e.g. the behavior of the conditional operator on l-values in terms of reference binding. I apologize. >> >> ...I see that this adds a new special case to exception handling. >> >> Yes; I'd forgotten to mention this side of the ABI change. >> >> We'll also need a new flag on type_info objects to model this. In line with the transaction_safe changes that Jason proposed, I suggest adding a __noexcept_mask = 0x40 to __pbase_type_info, and representing a pointer to noexcept function as a pointer with __noexcept_mask bit set to the corresponding *non-noexcept* function pointer type. > > I strongly disagree; we should take this opportunity to revisit that decision. The floodgates are open, and this set of function type attributes is clearly going to grow over time. (It's actually transaction_safe that really drives this point home; noexcept is at least a longstanding part of the core language in various forms.) We also have a lot of vendor-specific function type attributes that are part of the type but just aren't standardized and can't be represented in type_info. I don't think it makes sense to indefinitely keep hacking these things into the pointer type flags; we should just bite the bullet and create a new function_type_info subclass. Oh, for what it's worth, this is actually mandatory: typeid does have to be able to return a type_info for an arbitrary type, not just a pointer or member pointer for it. typeid does not perform function-to-pointer conversion on an expression operand, and it can also be used with an arbitrary type-id. > OK. How about this: > > class __qualified_function_type_info : public __function_type_info { > public: > const __function_type_info *__base_type; > unsigned int __qualifiers; > enum __qualifiers_mask { > __const_mask = 0x01, > __volatile_mask = 0x02, > __restrict_mask = 0x04, > __lval_ref_mask = 0x08, > __rval_ref_mask = 0x10, > __noexcept_mask = 0x20, > __transaction_safe_mask = 0x40 > }; > }; > > ... where __base_type is the unqualified function type, included to avoid the need for string comparisons when checking for a matching exception handler. The base class __function_type_info would be used for types with no qualifiers. Representing the base type this way makes sense to me. Adding a new class does have backwards deployment problems: normally these type_infos are emitted by the ABI library, but it won't have this class on older targets. I don't think we want to lazily emit this class in every translation unit that uses it; that's a lot of code, including some that's intricately tied to the EH mechanism. On Darwin, I don't have any problem with saying that we just don't support the extended information unless the minimum deployment target is an OS that provides the class; after all, the exceptions machinery won't support it without updates either. Is a similar answer acceptable to other people, or do we need something more sophisticated? > It might also be reasonable to reserve a bit for 'noreturn', since several compilers treat it as part of the function type in some way. I'm not sure this is the right representation for function type qualifiers. It seems to me that there are two kinds: - those that create a (trivially-convertible) subtype of the unqualified type, like 'unwind', 'noexcept', and (for the implementations that make this decision) 'noreturn', and - those that don't, like cvr-qualifiers, ref-qualifiers, and calling conventions. EH matching needs to verify that the subtyping qualifiers of the source type are a superset of the subtyping qualifiers of the target type, and it needs to verify that the other qualifiers match exactly. I don't think catch-matching on a qualified function pointer type is an operation we need to expend a lot of effort optimizing. I would rather have a more general representation that allows fairly painless vendor extension; I think that calls for at least the ability to have *some* string-based matching, even if maybe the standard ones get allocated to bit-fields. John. -------------- next part -------------- An HTML attachment was scrubbed... URL: From richardsmith at google.com Thu Oct 13 00:07:50 2016 From: richardsmith at google.com (Richard Smith) Date: Wed, 12 Oct 2016 17:07:50 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: <52713467-E6E0-4B91-8F79-EB5D34E905AD@apple.com> References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> <52713467-E6E0-4B91-8F79-EB5D34E905AD@apple.com> Message-ID: On 12 October 2016 at 16:34, John McCall wrote: > > On Oct 12, 2016, at 2:09 PM, Richard Smith > wrote: > > On 12 October 2016 at 13:51, John McCall wrote: > >> On Oct 12, 2016, at 11:58 AM, Richard Smith >> wrote: >> On 11 October 2016 at 19:20, John McCall wrote: >> >>> On Oct 11, 2016, at 4:20 PM, Richard Smith >>> wrote: >>> On 11 October 2016 at 15:17, John McCall wrote: >>> >>>> On Oct 11, 2016, at 2:11 PM, Richard Smith >>>> wrote: >>>> Under >>>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html >>>> >>>> the noexceptness of a function type is now part of the type. As a >>>> result, we need manglings for exception-specifications on function >>>> pointer/reference types: >>>> >>>> void f(void()) {} >>>> void f(void() noexcept) {} // ok, overload not redefinition >>>> >>>> (It's not clear to me whether or not this was also necessary prior to >>>> C++17 to handle dependent exception specifications that appear lexically >>>> within the parameter list of a function template, and actual implementation >>>> practice varies as to whether such exception specifications are SFINAEable.) >>>> >>>> >>>> In order to handle overloading/SFINAE on exception specifications in >>>> dependent cases, we need to be able to mangle not only "noexcept", but also >>>> "noexcept(expression)" and "throw()". Suggestion for manglings: >>>> >>>> ::= >>>> nx -- non-throwing exception specification >>>> nX E -- computed (value-dependent) noexcept >>>> tw * E -- throw (types) >>>> >>>> ::= [] [] [Dx] F [Y] >>>> [] E >>>> >>>> In the case of throw(a, b, c), we could omit types that are neither >>>> instantiation-dependent nor pack expansions (if that omits all types, we >>>> can use the 'nx' mangling instead), since C++17 says you can't overload on >>>> the actual types in the dynamic exception specification, and we otherwise >>>> only need them to be present if they might result in a substitution failure. >>>> >>>> Thoughts? >>>> >>>> >>>> I think this is an amazingly late change to the language with pretty >>>> thin justification; does that count? >>>> >>>> This really is a major change which can reasonably be expected to cause >>>> substantial source and binary breakage. The proposal mentions >>>> transaction_safe as a feature that added similar complexity, but that >>>> analogy is weak because (1) TM is expected to be an optional TS, whereas >>>> noexcept is a mandatory core language feature, and (2) existing code does >>>> not use the transaction_safe attribute, whereas noexcept and throw() have >>>> seen widespread adoption, in the latter case for years. >>>> >>>> If it is a goal of this proposal to eliminate the underspecified fake >>>> type system around exception specifications, it is worth noting that it >>>> completely fails to do so, since the checking rules for direct function >>>> pointer assignments are still quite a bit stronger than those provided by >>>> the new type system. >>>> >>> >>> That was indeed a goal here. Can you expand on how it fails? Ignoring >>> the (deprecated) dynamic exception specifications, this new approach seems >>> stronger than the old type system, since it works for function types being >>> arbitrarily nested within other types, not just one level deep within >>> function types and pointers. >>> >>> >>> Are there any implementations which actually plan to throw out the >>> dynamic exception specification matching logic? >>> >> >> *shrug* Maybe MSVC? Any conforming C++17 implementation will need to >> demote that side of their enforcement to a warning. And I think there are >> NB comments for C++17 proposing that we apply http://www.open-std.org/ >> jtc1/sc22/wg21/docs/papers/2016/p0003r4.html for C++17 rather than >> waiting for C++20. >> >> >> Not enforcing the old rules is also compatibility-breaking, of course, >> because of SFINAE. >> >> Hmm, I thought we had added a rule to allow B to be deduced in >>> >>> template void f(R(A...) noexcept(B)); >>> >>> but it looks like we actually didn't. =( >>> >>> >>> Hmm, that would work pretty well for this case. >>> >>> Yes, the above is a problem, if noexcept function types start to appear >>> in existing code (for instance through use of decltype or by code that >>> passes around noexcept function pointers). >>> >>> >>> Well, recall that noexcept function types have always been writable; >>> they just didn't necessarily get enforced reliably. Also, noexcept and >>> throw() are pretty popular, and aren't there proposals to infer them in >>> more cases? >>> >> >> Proposals, yes, but nothing in C++17. >> >> >> I think it's reasonable to anticipate that when judging how often >> functions will be noexcept. >> >> >> It's really hard to say abstractly how much impact this will have. >>> There's a lot of potential for breakage, but it's also quite possible that >>> there won't be many changes and that almost all of them will be lost in the >>> great grey expanse of C++ binary compatibility. >>> >> >> We'll have an implementation soon, and then we can find out whether this >> is a problem in practice. >> >> >> I'll admit that I don't attend committee meetings, but I thought that >> implementation experience was expected *prior* to standardization, not >> something that gets done months after voting the thing in concurrently with >> the committee finalizing the language in a draft for next year's release. >> > > Some of us try to push for that. So far we've not had much success. > > > A pity. > > Okay. Doug Gregor has strong opinions about this, but I'll let him speak > for himself if he wants; I'll drop my own objections to the feature pending > implementation experience. > > You will note that I have omitted the necessary specializations for >>>> "transaction_safe", as well as the incredibly common extension of >>>> specialized calling conventions. >>>> >>>> This also breaks source compatibility for template matching, and >>>> basically every function template in the standard library is going to >>>> change manglings (and become *much* larger) due to noexcept expressions now >>>> being mangled. >>>> >>> >>> It's a problem, but I don't think it's as bad as you claim. The mangling >>> of a function still wouldn't include its exception specification; this >>> would only affect mangling in cases where a parameter or return type or >>> template argument involves a function type with an exception-specification >>> -- a lot less common than every function template in the standard library, >>> but this still does change manglings for existing code. >>> >>> >>> Okay, so it only triggers SFINAE failures in nested function types, and >>> you can't overload templates by it? I agree that that helps a lot. >>> >>> And the entire proposal seems to have forgotten about >>>> reference-to-function types. >>>> >>> >>> The change to [dcl.init.ref]p4 allows a reference to non-noexcept >>> function to bind to a noexcept function, and this indirectly allows the >>> same during overload resolution, casts, and so on. What additional >>> considerations were missed? >>> >>> >>> I hadn't realized that the expression logic was so consistent about >>> defining e.g. the behavior of the conditional operator on l-values in terms >>> of reference binding. I apologize. >>> >>> ...I see that this adds a new special case to exception handling. >>> >> >> Yes; I'd forgotten to mention this side of the ABI change. >> >> We'll also need a new flag on type_info objects to model this. In line >> with the transaction_safe changes that Jason proposed, I suggest adding a >> __noexcept_mask = 0x40 to __pbase_type_info, and representing a pointer to >> noexcept function as a pointer with __noexcept_mask bit set to the >> corresponding *non-noexcept* function pointer type. >> >> >> I strongly disagree; we should take this opportunity to revisit that >> decision. The floodgates are open, and this set of function type >> attributes is clearly going to grow over time. (It's actually >> transaction_safe that really drives this point home; noexcept is at least a >> longstanding part of the core language in various forms.) We also have a >> lot of vendor-specific function type attributes that are part of the type >> but just aren't standardized and can't be represented in type_info. I >> don't think it makes sense to indefinitely keep hacking these things into >> the pointer type flags; we should just bite the bullet and create a new >> function_type_info subclass. >> > > Oh, for what it's worth, this is actually mandatory: typeid does have to > be able to return a type_info for an arbitrary type, not just a pointer or > member pointer for it. typeid does not perform function-to-pointer > conversion on an expression operand, and it can also be used with an > arbitrary type-id. > We definitely need different type_info for the qualified and unqualified types, but I don't think that implies that the pointee type in the type_info for corresponding function pointers must be different. GCC's approach for transaction_safe is that the pointee type_info referenced by a pointer type_info is always the function type *without* the transaction_safe mangling, so the marking is present only on the pointer type_info. That's definitely not ideal, but does seem to work. That said, I like the end result of this approach a lot more: > OK. How about this: > > class __qualified_function_type_info : public __function_type_info { > public: > const __function_type_info *__base_type; > unsigned int __qualifiers; > enum __qualifiers_mask { > __const_mask = 0x01, > __volatile_mask = 0x02, > __restrict_mask = 0x04, > __lval_ref_mask = 0x08, > __rval_ref_mask = 0x10, > __noexcept_mask = 0x20, > __transaction_safe_mask = 0x40 > }; > }; > > ... where __base_type is the unqualified function type, included to avoid > the need for string comparisons when checking for a matching exception > handler. The base class __function_type_info would be used for types with > no qualifiers. > > > Representing the base type this way makes sense to me. > > Adding a new class does have backwards deployment problems: normally these > type_infos are emitted by the ABI library, but it won't have this class on > older targets. I don't think we want to lazily emit this class in every > translation unit that uses it; that's a lot of code, including some that's > intricately tied to the EH mechanism. On Darwin, I don't have any problem > with saying that we just don't support the extended information unless the > minimum deployment target is an OS that provides the class; after all, the > exceptions machinery won't support it without updates either. Is a similar > answer acceptable to other people, or do we need something more > sophisticated? > It's definitely a pain for Clang targeting GNU OSs, since we support using the installed version of libsupc++ as our ABI library. If the only fallout were that you couldn't throw a noexcept function pointer and catch it as a non-noexcept function pointer, that'd be fine, but link errors for the __qualified_function_type_info vtable seem problematic. We could potentially lazily emit that one symbol as a weak alias for the __function_type_info vtable, but we tried something like that with sized deallocation (which had largely similar issues) and found it to be more trouble than it was worth. > It might also be reasonable to reserve a bit for 'noreturn', since several > compilers treat it as part of the function type in some way. > > > I'm not sure this is the right representation for function type > qualifiers. It seems to me that there are two kinds: > - those that create a (trivially-convertible) subtype of the unqualified > type, like 'unwind', 'noexcept', and (for the implementations that make > this decision) 'noreturn', and > - those that don't, like cvr-qualifiers, ref-qualifiers, and calling > conventions. > There's been some recent talk of permitting pointer-to-member-function conversions that remove cvr-qualifiers and add ref-qualifiers; those two may end up in the "trivially-convertible" camp for C++20. http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1555 suggests allowing implicit conversion between extern "C" function types and non-extern-"C" function types in cases where the two calling conventions are the same, as a way of resolving the issues leading to longstanding lack of implementation of extern "C" function types by most vendors. But I would certainly grant that it doesn't make sense to use these flags to model, for instance, actually-different calling conventions. > EH matching needs to verify that the subtyping qualifiers of the source > type are a superset of the subtyping qualifiers of the target type, and it > needs to verify that the other qualifiers match exactly. > > I don't think catch-matching on a qualified function pointer type is an > operation we need to expend a lot of effort optimizing. I would rather > have a more general representation that allows fairly painless vendor > extension; I think that calls for at least the ability to have *some* > string-based matching, even if maybe the standard ones get allocated to > bit-fields. > > John. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rjmccall at apple.com Thu Oct 13 17:39:43 2016 From: rjmccall at apple.com (John McCall) Date: Thu, 13 Oct 2016 10:39:43 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> <52713467-E6E0-4B91-8F79-EB5D34E905AD@apple.com> Message-ID: > On Oct 12, 2016, at 5:07 PM, Richard Smith wrote: > On 12 October 2016 at 16:34, John McCall > wrote: > >> On Oct 12, 2016, at 2:09 PM, Richard Smith > wrote: >> >> On 12 October 2016 at 13:51, John McCall > wrote: >>> On Oct 12, 2016, at 11:58 AM, Richard Smith > wrote: >>> On 11 October 2016 at 19:20, John McCall > wrote: >>>> On Oct 11, 2016, at 4:20 PM, Richard Smith > wrote: >>>> On 11 October 2016 at 15:17, John McCall > wrote: >>>>> On Oct 11, 2016, at 2:11 PM, Richard Smith > wrote: >>>>> Under >>>>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html >>>>> >>>>> the noexceptness of a function type is now part of the type. As a result, we need manglings for exception-specifications on function pointer/reference types: >>>>> >>>>> void f(void()) {} >>>>> void f(void() noexcept) {} // ok, overload not redefinition >>>>> >>>>> (It's not clear to me whether or not this was also necessary prior to C++17 to handle dependent exception specifications that appear lexically within the parameter list of a function template, and actual implementation practice varies as to whether such exception specifications are SFINAEable.) >>>>> >>>>> >>>>> In order to handle overloading/SFINAE on exception specifications in dependent cases, we need to be able to mangle not only "noexcept", but also "noexcept(expression)" and "throw()". Suggestion for manglings: >>>>> >>>>> ::= >>>>> nx -- non-throwing exception specification >>>>> nX E -- computed (value-dependent) noexcept >>>>> tw * E -- throw (types) >>>>> >>>>> ::= [] [] [Dx] F [Y] [] E >>>>> >>>>> In the case of throw(a, b, c), we could omit types that are neither instantiation-dependent nor pack expansions (if that omits all types, we can use the 'nx' mangling instead), since C++17 says you can't overload on the actual types in the dynamic exception specification, and we otherwise only need them to be present if they might result in a substitution failure. >>>>> >>>>> Thoughts? >>>> >>>> I think this is an amazingly late change to the language with pretty thin justification; does that count? >>>> >>>> This really is a major change which can reasonably be expected to cause substantial source and binary breakage. The proposal mentions transaction_safe as a feature that added similar complexity, but that analogy is weak because (1) TM is expected to be an optional TS, whereas noexcept is a mandatory core language feature, and (2) existing code does not use the transaction_safe attribute, whereas noexcept and throw() have seen widespread adoption, in the latter case for years. >>>> >>>> If it is a goal of this proposal to eliminate the underspecified fake type system around exception specifications, it is worth noting that it completely fails to do so, since the checking rules for direct function pointer assignments are still quite a bit stronger than those provided by the new type system. >>>> >>>> That was indeed a goal here. Can you expand on how it fails? Ignoring the (deprecated) dynamic exception specifications, this new approach seems stronger than the old type system, since it works for function types being arbitrarily nested within other types, not just one level deep within function types and pointers. >>> >>> Are there any implementations which actually plan to throw out the dynamic exception specification matching logic? >>> >>> *shrug* Maybe MSVC? Any conforming C++17 implementation will need to demote that side of their enforcement to a warning. And I think there are NB comments for C++17 proposing that we apply http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0003r4.html for C++17 rather than waiting for C++20. >> >> Not enforcing the old rules is also compatibility-breaking, of course, because of SFINAE. >> >>>> Hmm, I thought we had added a rule to allow B to be deduced in >>>> >>>> template void f(R(A...) noexcept(B)); >>>> >>>> but it looks like we actually didn't. =( >>> >>> Hmm, that would work pretty well for this case. >>> >>>> Yes, the above is a problem, if noexcept function types start to appear in existing code (for instance through use of decltype or by code that passes around noexcept function pointers). >>> >>> Well, recall that noexcept function types have always been writable; they just didn't necessarily get enforced reliably. Also, noexcept and throw() are pretty popular, and aren't there proposals to infer them in more cases? >>> >>> Proposals, yes, but nothing in C++17. >> >> I think it's reasonable to anticipate that when judging how often functions will be noexcept. >> >>> It's really hard to say abstractly how much impact this will have. There's a lot of potential for breakage, but it's also quite possible that there won't be many changes and that almost all of them will be lost in the great grey expanse of C++ binary compatibility. >>> >>> We'll have an implementation soon, and then we can find out whether this is a problem in practice. >> >> I'll admit that I don't attend committee meetings, but I thought that implementation experience was expected *prior* to standardization, not something that gets done months after voting the thing in concurrently with the committee finalizing the language in a draft for next year's release. >> >> Some of us try to push for that. So far we've not had much success. > > A pity. > > Okay. Doug Gregor has strong opinions about this, but I'll let him speak for himself if he wants; I'll drop my own objections to the feature pending implementation experience. > >>>> You will note that I have omitted the necessary specializations for "transaction_safe", as well as the incredibly common extension of specialized calling conventions. >>>> >>>> This also breaks source compatibility for template matching, and basically every function template in the standard library is going to change manglings (and become *much* larger) due to noexcept expressions now being mangled. >>>> >>>> It's a problem, but I don't think it's as bad as you claim. The mangling of a function still wouldn't include its exception specification; this would only affect mangling in cases where a parameter or return type or template argument involves a function type with an exception-specification -- a lot less common than every function template in the standard library, but this still does change manglings for existing code. >>> >>> Okay, so it only triggers SFINAE failures in nested function types, and you can't overload templates by it? I agree that that helps a lot. >>>> And the entire proposal seems to have forgotten about reference-to-function types. >>>> >>>> The change to [dcl.init.ref]p4 allows a reference to non-noexcept function to bind to a noexcept function, and this indirectly allows the same during overload resolution, casts, and so on. What additional considerations were missed? >>> >>> I hadn't realized that the expression logic was so consistent about defining e.g. the behavior of the conditional operator on l-values in terms of reference binding. I apologize. >>> >>> ...I see that this adds a new special case to exception handling. >>> >>> Yes; I'd forgotten to mention this side of the ABI change. >>> >>> We'll also need a new flag on type_info objects to model this. In line with the transaction_safe changes that Jason proposed, I suggest adding a __noexcept_mask = 0x40 to __pbase_type_info, and representing a pointer to noexcept function as a pointer with __noexcept_mask bit set to the corresponding *non-noexcept* function pointer type. >> >> I strongly disagree; we should take this opportunity to revisit that decision. The floodgates are open, and this set of function type attributes is clearly going to grow over time. (It's actually transaction_safe that really drives this point home; noexcept is at least a longstanding part of the core language in various forms.) We also have a lot of vendor-specific function type attributes that are part of the type but just aren't standardized and can't be represented in type_info. I don't think it makes sense to indefinitely keep hacking these things into the pointer type flags; we should just bite the bullet and create a new function_type_info subclass. > > Oh, for what it's worth, this is actually mandatory: typeid does have to be able to return a type_info for an arbitrary type, not just a pointer or member pointer for it. typeid does not perform function-to-pointer conversion on an expression operand, and it can also be used with an arbitrary type-id. > > We definitely need different type_info for the qualified and unqualified types, but I don't think that implies that the pointee type in the type_info for corresponding function pointers must be different. GCC's approach for transaction_safe is that the pointee type_info referenced by a pointer type_info is always the function type *without* the transaction_safe mangling, so the marking is present only on the pointer type_info. That's definitely not ideal, but does seem to work. Ah, I think I see. You're suggesting that the type_info for 'void(*)() noexcept' could just be an attributed pointer to the type_info for 'void()', but that the type_info for 'void() noexcept' would be some different sort of thing. I agree that this is possible, but it might paint us into a corner; e.g. if the committee ever standardizes a richer reflection system based on type_info, I would expect it to have some way to ask for the pointee type of a pointer as a type_info, which we would then be unable to implement correctly. > That said, I like the end result of this approach a lot more: >> OK. How about this: >> >> class __qualified_function_type_info : public __function_type_info { >> public: >> const __function_type_info *__base_type; >> unsigned int __qualifiers; >> enum __qualifiers_mask { >> __const_mask = 0x01, >> __volatile_mask = 0x02, >> __restrict_mask = 0x04, >> __lval_ref_mask = 0x08, >> __rval_ref_mask = 0x10, >> __noexcept_mask = 0x20, >> __transaction_safe_mask = 0x40 >> }; >> }; >> >> ... where __base_type is the unqualified function type, included to avoid the need for string comparisons when checking for a matching exception handler. The base class __function_type_info would be used for types with no qualifiers. > > Representing the base type this way makes sense to me. > > Adding a new class does have backwards deployment problems: normally these type_infos are emitted by the ABI library, but it won't have this class on older targets. I don't think we want to lazily emit this class in every translation unit that uses it; that's a lot of code, including some that's intricately tied to the EH mechanism. On Darwin, I don't have any problem with saying that we just don't support the extended information unless the minimum deployment target is an OS that provides the class; after all, the exceptions machinery won't support it without updates either. Is a similar answer acceptable to other people, or do we need something more sophisticated? > > It's definitely a pain for Clang targeting GNU OSs, since we support using the installed version of libsupc++ as our ABI library. If the only fallout were that you couldn't throw a noexcept function pointer and catch it as a non-noexcept function pointer, that'd be fine, but link errors for the __qualified_function_type_info vtable seem problematic. > > We could potentially lazily emit that one symbol as a weak alias for the __function_type_info vtable, but we tried something like that with sized deallocation (which had largely similar issues) and found it to be more trouble than it was worth. I don't remember all the issues for sized deallocation, but at least some of them wouldn't apply here. IIRC, sized deallocation actually had to be a weak alias to a local implementation in order to satisfy the ABI / delegation rules, which wouldn't be true here. More importantly, sized deallocation required adding code to the majority of translation units, which, uh, I don't expect we'll see similar problems from here. Still, this is asking a lot of of the linker/loader. We can avoid introducing the new class if we can find some other way to encode in the object that it has extra fields. Unfortunately, a __function_type_info only has a v-table pointer (inviolate) and a name pointer (just a const char*, i.e. 1-byte aligned). We can't put anything in the string itself because it has to be globally uniqued, and if our name "wins" and is used in a different type_info which doesn't provide the extra fields, we're in trouble. So I don't think this is possible. But lazily emitting the v-table also creates nasty problems, chiefly because it requires us to also emit the virtual function definitions lazily, and those are pretty complex. Can we emit a weak definition in the compiler runtime library, or does that have the same problems as a weak definition in every translation unit? >> It might also be reasonable to reserve a bit for 'noreturn', since several compilers treat it as part of the function type in some way. > > I'm not sure this is the right representation for function type qualifiers. It seems to me that there are two kinds: > - those that create a (trivially-convertible) subtype of the unqualified type, like 'unwind', 'noexcept', and (for the implementations that make this decision) 'noreturn', and > - those that don't, like cvr-qualifiers, ref-qualifiers, and calling conventions. > > There's been some recent talk of permitting pointer-to-member-function conversions that remove cvr-qualifiers and add ref-qualifiers; those two may end up in the "trivially-convertible" camp for C++20. > > http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1555 suggests allowing implicit conversion between extern "C" function types and non-extern-"C" function types in cases where the two calling conventions are the same, as a way of resolving the issues leading to longstanding lack of implementation of extern "C" function types by most vendors. Okay, I accept that the standardized attributes should just be represented as specific bits and that baking subtyping into the representation is fraught. So maybe the representation should be: class __qualified_function_type_info : public __function_type_info { public: const __function_type_info *__base_type; unsigned int __qualifiers; enum __qualifiers_mask { __const_mask = 0x01, __volatile_mask = 0x02, __restrict_mask = 0x04, __lval_ref_mask = 0x08, __rval_ref_mask = 0x10, __noexcept_mask = 0x20, __transaction_safe_mask = 0x40 }; const char *__extended_qualifiers; }; And the convertibility check requires the extended qualifiers to either both be null or string-compare equal. John. > > But I would certainly grant that it doesn't make sense to use these flags to model, for instance, actually-different calling conventions. > > EH matching needs to verify that the subtyping qualifiers of the source type are a superset of the subtyping qualifiers of the target type, and it needs to verify that the other qualifiers match exactly. > > I don't think catch-matching on a qualified function pointer type is an operation we need to expend a lot of effort optimizing. I would rather have a more general representation that allows fairly painless vendor extension; I think that calls for at least the ability to have *some* string-based matching, even if maybe the standard ones get allocated to bit-fields. > > John. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From richardsmith at google.com Thu Oct 13 18:29:47 2016 From: richardsmith at google.com (Richard Smith) Date: Thu, 13 Oct 2016 11:29:47 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> <52713467-E6E0-4B91-8F79-EB5D34E905AD@apple.com> Message-ID: On 13 October 2016 at 10:39, John McCall wrote: > On Oct 12, 2016, at 5:07 PM, Richard Smith > wrote: > On 12 October 2016 at 16:34, John McCall wrote: > >> >> On Oct 12, 2016, at 2:09 PM, Richard Smith >> wrote: >> >> On 12 October 2016 at 13:51, John McCall wrote: >> >>> On Oct 12, 2016, at 11:58 AM, Richard Smith >>> wrote: >>> On 11 October 2016 at 19:20, John McCall wrote: >>> >>>> On Oct 11, 2016, at 4:20 PM, Richard Smith >>>> wrote: >>>> On 11 October 2016 at 15:17, John McCall wrote: >>>> >>>>> On Oct 11, 2016, at 2:11 PM, Richard Smith >>>>> wrote: >>>>> Under >>>>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html >>>>> >>>>> the noexceptness of a function type is now part of the type. As a >>>>> result, we need manglings for exception-specifications on function >>>>> pointer/reference types: >>>>> >>>>> void f(void()) {} >>>>> void f(void() noexcept) {} // ok, overload not redefinition >>>>> >>>>> (It's not clear to me whether or not this was also necessary prior to >>>>> C++17 to handle dependent exception specifications that appear lexically >>>>> within the parameter list of a function template, and actual implementation >>>>> practice varies as to whether such exception specifications are SFINAEable.) >>>>> >>>>> >>>>> In order to handle overloading/SFINAE on exception specifications in >>>>> dependent cases, we need to be able to mangle not only "noexcept", but also >>>>> "noexcept(expression)" and "throw()". Suggestion for manglings: >>>>> >>>>> ::= >>>>> nx -- non-throwing exception specification >>>>> nX E -- computed (value-dependent) noexcept >>>>> tw * E -- throw (types) >>>>> >>>>> ::= [] [] [Dx] F [Y] >>>>> [] E >>>>> >>>>> In the case of throw(a, b, c), we could omit types that are neither >>>>> instantiation-dependent nor pack expansions (if that omits all types, we >>>>> can use the 'nx' mangling instead), since C++17 says you can't overload on >>>>> the actual types in the dynamic exception specification, and we otherwise >>>>> only need them to be present if they might result in a substitution failure. >>>>> >>>>> Thoughts? >>>>> >>>>> >>>>> I think this is an amazingly late change to the language with pretty >>>>> thin justification; does that count? >>>>> >>>>> This really is a major change which can reasonably be expected to >>>>> cause substantial source and binary breakage. The proposal mentions >>>>> transaction_safe as a feature that added similar complexity, but that >>>>> analogy is weak because (1) TM is expected to be an optional TS, whereas >>>>> noexcept is a mandatory core language feature, and (2) existing code does >>>>> not use the transaction_safe attribute, whereas noexcept and throw() have >>>>> seen widespread adoption, in the latter case for years. >>>>> >>>>> If it is a goal of this proposal to eliminate the underspecified fake >>>>> type system around exception specifications, it is worth noting that it >>>>> completely fails to do so, since the checking rules for direct function >>>>> pointer assignments are still quite a bit stronger than those provided by >>>>> the new type system. >>>>> >>>> >>>> That was indeed a goal here. Can you expand on how it fails? Ignoring >>>> the (deprecated) dynamic exception specifications, this new approach seems >>>> stronger than the old type system, since it works for function types being >>>> arbitrarily nested within other types, not just one level deep within >>>> function types and pointers. >>>> >>>> >>>> Are there any implementations which actually plan to throw out the >>>> dynamic exception specification matching logic? >>>> >>> >>> *shrug* Maybe MSVC? Any conforming C++17 implementation will need to >>> demote that side of their enforcement to a warning. And I think there are >>> NB comments for C++17 proposing that we apply http://www.open-std.org/ >>> jtc1/sc22/wg21/docs/papers/2016/p0003r4.html for C++17 rather than >>> waiting for C++20. >>> >>> >>> Not enforcing the old rules is also compatibility-breaking, of course, >>> because of SFINAE. >>> >>> Hmm, I thought we had added a rule to allow B to be deduced in >>>> >>>> template void f(R(A...) noexcept(B)); >>>> >>>> but it looks like we actually didn't. =( >>>> >>>> >>>> Hmm, that would work pretty well for this case. >>>> >>>> Yes, the above is a problem, if noexcept function types start to appear >>>> in existing code (for instance through use of decltype or by code that >>>> passes around noexcept function pointers). >>>> >>>> >>>> Well, recall that noexcept function types have always been writable; >>>> they just didn't necessarily get enforced reliably. Also, noexcept and >>>> throw() are pretty popular, and aren't there proposals to infer them in >>>> more cases? >>>> >>> >>> Proposals, yes, but nothing in C++17. >>> >>> >>> I think it's reasonable to anticipate that when judging how often >>> functions will be noexcept. >>> >>> >>> It's really hard to say abstractly how much impact this will have. >>>> There's a lot of potential for breakage, but it's also quite possible that >>>> there won't be many changes and that almost all of them will be lost in the >>>> great grey expanse of C++ binary compatibility. >>>> >>> >>> We'll have an implementation soon, and then we can find out whether this >>> is a problem in practice. >>> >>> >>> I'll admit that I don't attend committee meetings, but I thought that >>> implementation experience was expected *prior* to standardization, not >>> something that gets done months after voting the thing in concurrently with >>> the committee finalizing the language in a draft for next year's release. >>> >> >> Some of us try to push for that. So far we've not had much success. >> >> >> A pity. >> >> Okay. Doug Gregor has strong opinions about this, but I'll let him speak >> for himself if he wants; I'll drop my own objections to the feature pending >> implementation experience. >> >> You will note that I have omitted the necessary specializations for >>>>> "transaction_safe", as well as the incredibly common extension of >>>>> specialized calling conventions. >>>>> >>>>> This also breaks source compatibility for template matching, and >>>>> basically every function template in the standard library is going to >>>>> change manglings (and become *much* larger) due to noexcept expressions now >>>>> being mangled. >>>>> >>>> >>>> It's a problem, but I don't think it's as bad as you claim. The >>>> mangling of a function still wouldn't include its exception specification; >>>> this would only affect mangling in cases where a parameter or return type >>>> or template argument involves a function type with an >>>> exception-specification -- a lot less common than every function template >>>> in the standard library, but this still does change manglings for existing >>>> code. >>>> >>>> >>>> Okay, so it only triggers SFINAE failures in nested function types, and >>>> you can't overload templates by it? I agree that that helps a lot. >>>> >>>> And the entire proposal seems to have forgotten about >>>>> reference-to-function types. >>>>> >>>> >>>> The change to [dcl.init.ref]p4 allows a reference to non-noexcept >>>> function to bind to a noexcept function, and this indirectly allows the >>>> same during overload resolution, casts, and so on. What additional >>>> considerations were missed? >>>> >>>> >>>> I hadn't realized that the expression logic was so consistent about >>>> defining e.g. the behavior of the conditional operator on l-values in terms >>>> of reference binding. I apologize. >>>> >>>> ...I see that this adds a new special case to exception handling. >>>> >>> >>> Yes; I'd forgotten to mention this side of the ABI change. >>> >>> We'll also need a new flag on type_info objects to model this. In line >>> with the transaction_safe changes that Jason proposed, I suggest adding a >>> __noexcept_mask = 0x40 to __pbase_type_info, and representing a pointer to >>> noexcept function as a pointer with __noexcept_mask bit set to the >>> corresponding *non-noexcept* function pointer type. >>> >>> >>> I strongly disagree; we should take this opportunity to revisit that >>> decision. The floodgates are open, and this set of function type >>> attributes is clearly going to grow over time. (It's actually >>> transaction_safe that really drives this point home; noexcept is at least a >>> longstanding part of the core language in various forms.) We also have a >>> lot of vendor-specific function type attributes that are part of the type >>> but just aren't standardized and can't be represented in type_info. I >>> don't think it makes sense to indefinitely keep hacking these things into >>> the pointer type flags; we should just bite the bullet and create a new >>> function_type_info subclass. >>> >> >> Oh, for what it's worth, this is actually mandatory: typeid does have to >> be able to return a type_info for an arbitrary type, not just a pointer or >> member pointer for it. typeid does not perform function-to-pointer >> conversion on an expression operand, and it can also be used with an >> arbitrary type-id. >> > > We definitely need different type_info for the qualified and unqualified > types, but I don't think that implies that the pointee type in the > type_info for corresponding function pointers must be different. GCC's > approach for transaction_safe is that the pointee type_info referenced by a > pointer type_info is always the function type *without* the > transaction_safe mangling, so the marking is present only on the pointer > type_info. That's definitely not ideal, but does seem to work. > > > Ah, I think I see. You're suggesting that the type_info for 'void(*)() > noexcept' could just be an attributed pointer to the type_info for > 'void()', but that the type_info for 'void() noexcept' would be some > different sort of thing. I agree that this is possible, but it might paint > us into a corner; e.g. if the committee ever standardizes a richer > reflection system based on type_info, I would expect it to have some way to > ask for the pointee type of a pointer as a type_info, which we would then > be unable to implement correctly. > > That said, I like the end result of this approach a lot more: > >> OK. How about this: >> >> class __qualified_function_type_info : public __function_type_info { >> public: >> const __function_type_info *__base_type; >> unsigned int __qualifiers; >> enum __qualifiers_mask { >> __const_mask = 0x01, >> __volatile_mask = 0x02, >> __restrict_mask = 0x04, >> __lval_ref_mask = 0x08, >> __rval_ref_mask = 0x10, >> __noexcept_mask = 0x20, >> __transaction_safe_mask = 0x40 >> }; >> }; >> >> ... where __base_type is the unqualified function type, included to avoid >> the need for string comparisons when checking for a matching exception >> handler. The base class __function_type_info would be used for types with >> no qualifiers. >> >> >> Representing the base type this way makes sense to me. >> >> Adding a new class does have backwards deployment problems: normally >> these type_infos are emitted by the ABI library, but it won't have this >> class on older targets. I don't think we want to lazily emit this class in >> every translation unit that uses it; that's a lot of code, including some >> that's intricately tied to the EH mechanism. On Darwin, I don't have any >> problem with saying that we just don't support the extended information >> unless the minimum deployment target is an OS that provides the class; >> after all, the exceptions machinery won't support it without updates >> either. Is a similar answer acceptable to other people, or do we need >> something more sophisticated? >> > > It's definitely a pain for Clang targeting GNU OSs, since we support using > the installed version of libsupc++ as our ABI library. If the only fallout > were that you couldn't throw a noexcept function pointer and catch it as a > non-noexcept function pointer, that'd be fine, but link errors for the > __qualified_function_type_info vtable seem problematic. > > We could potentially lazily emit that one symbol as a weak alias for the > __function_type_info vtable, but we tried something like that with sized > deallocation (which had largely similar issues) and found it to be more > trouble than it was worth. > > > I don't remember all the issues for sized deallocation, but at least some > of them wouldn't apply here. IIRC, sized deallocation actually had to be a > weak alias to a local implementation in order to satisfy the ABI / > delegation rules, which wouldn't be true here. More importantly, sized > deallocation required adding code to the majority of translation units, > which, uh, I don't expect we'll see similar problems from here. Still, > this is asking a lot of of the linker/loader. > The large number of duplicate copies was a pain, but wasn't the reason we ended up turning that mechanism off. I don't exactly recall the details, but the gist was that we needed linker magic to force a user replacement version from the main binary to be exported so that DSOs would see it, but that mechanism had problematic interactions with weak definitions. We can avoid introducing the new class if we can find some other way to > encode in the object that it has extra fields. Unfortunately, a > __function_type_info only has a v-table pointer (inviolate) and a name > pointer (just a const char*, i.e. 1-byte aligned). We can't put anything > in the string itself because it has to be globally uniqued, and if our name > "wins" and is used in a different type_info which doesn't provide the extra > fields, we're in trouble. So I don't think this is possible. > > But lazily emitting the v-table also creates nasty problems, chiefly > because it requires us to also emit the virtual function definitions > lazily, and those are pretty complex. > > Can we emit a weak definition in the compiler runtime library, or does > that have the same problems as a weak definition in every translation unit? > In our case, for some targets there simply is no compiler runtime library that we control. We might not even be involved in the link step. Perhaps we could use an ifunc selecting between the vtable of __qualified_function_type_info (if it's defined) and that of __function_type_info (otherwise) as the vptr of the type_info object for a qualified function type. > It might also be reasonable to reserve a bit for 'noreturn', since several >> compilers treat it as part of the function type in some way. >> >> >> I'm not sure this is the right representation for function type >> qualifiers. It seems to me that there are two kinds: >> - those that create a (trivially-convertible) subtype of the >> unqualified type, like 'unwind', 'noexcept', and (for the implementations >> that make this decision) 'noreturn', and >> - those that don't, like cvr-qualifiers, ref-qualifiers, and calling >> conventions. >> > > There's been some recent talk of permitting pointer-to-member-function > conversions that remove cvr-qualifiers and add ref-qualifiers; those two > may end up in the "trivially-convertible" camp for C++20. > > http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1555 suggests > allowing implicit conversion between extern "C" function types and > non-extern-"C" function types in cases where the two calling conventions > are the same, as a way of resolving the issues leading to longstanding lack > of implementation of extern "C" function types by most vendors. > > > Okay, I accept that the standardized attributes should just be represented > as specific bits and that baking subtyping into the representation is > fraught. So maybe the representation should be: > > class __qualified_function_type_info : public __function_type_info { > public: > const __function_type_info *__base_type; > unsigned int __qualifiers; > enum __qualifiers_mask { > __const_mask = 0x01, > __volatile_mask = 0x02, > __restrict_mask = 0x04, > __lval_ref_mask = 0x08, > __rval_ref_mask = 0x10, > __noexcept_mask = 0x20, > __transaction_safe_mask = 0x40 > }; > const char *__extended_qualifiers; > }; > > And the convertibility check requires the extended qualifiers to either > both be null or string-compare equal. > What does this buy us over keeping the extended qualifiers in the base type? Is the idea that a target-specific runtime could choose to allow more conversions based on extended qualifiers? > John. > > > But I would certainly grant that it doesn't make sense to use these flags > to model, for instance, actually-different calling conventions. > > >> EH matching needs to verify that the subtyping qualifiers of the source >> type are a superset of the subtyping qualifiers of the target type, and it >> needs to verify that the other qualifiers match exactly. >> >> I don't think catch-matching on a qualified function pointer type is an >> operation we need to expend a lot of effort optimizing. I would rather >> have a more general representation that allows fairly painless vendor >> extension; I think that calls for at least the ability to have *some* >> string-based matching, even if maybe the standard ones get allocated to >> bit-fields. >> >> John. >> > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rjmccall at apple.com Thu Oct 13 18:49:09 2016 From: rjmccall at apple.com (John McCall) Date: Thu, 13 Oct 2016 11:49:09 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> <52713467-E6E0-4B91-8F79-EB5D34E905AD@apple.com> Message-ID: > On Oct 13, 2016, at 11:29 AM, Richard Smith wrote: > On 13 October 2016 at 10:39, John McCall > wrote: >> On Oct 12, 2016, at 5:07 PM, Richard Smith > wrote: >> On 12 October 2016 at 16:34, John McCall > wrote: >> >>> On Oct 12, 2016, at 2:09 PM, Richard Smith > wrote: >>> >>> On 12 October 2016 at 13:51, John McCall > wrote: >>>> On Oct 12, 2016, at 11:58 AM, Richard Smith > wrote: >>>> On 11 October 2016 at 19:20, John McCall > wrote: >>>>> On Oct 11, 2016, at 4:20 PM, Richard Smith > wrote: >>>>> On 11 October 2016 at 15:17, John McCall > wrote: >>>>>> On Oct 11, 2016, at 2:11 PM, Richard Smith > wrote: >>>>>> Under >>>>>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html >>>>>> >>>>>> the noexceptness of a function type is now part of the type. As a result, we need manglings for exception-specifications on function pointer/reference types: >>>>>> >>>>>> void f(void()) {} >>>>>> void f(void() noexcept) {} // ok, overload not redefinition >>>>>> >>>>>> (It's not clear to me whether or not this was also necessary prior to C++17 to handle dependent exception specifications that appear lexically within the parameter list of a function template, and actual implementation practice varies as to whether such exception specifications are SFINAEable.) >>>>>> >>>>>> >>>>>> In order to handle overloading/SFINAE on exception specifications in dependent cases, we need to be able to mangle not only "noexcept", but also "noexcept(expression)" and "throw()". Suggestion for manglings: >>>>>> >>>>>> ::= >>>>>> nx -- non-throwing exception specification >>>>>> nX E -- computed (value-dependent) noexcept >>>>>> tw * E -- throw (types) >>>>>> >>>>>> ::= [] [] [Dx] F [Y] [] E >>>>>> >>>>>> In the case of throw(a, b, c), we could omit types that are neither instantiation-dependent nor pack expansions (if that omits all types, we can use the 'nx' mangling instead), since C++17 says you can't overload on the actual types in the dynamic exception specification, and we otherwise only need them to be present if they might result in a substitution failure. >>>>>> >>>>>> Thoughts? >>>>> >>>>> I think this is an amazingly late change to the language with pretty thin justification; does that count? >>>>> >>>>> This really is a major change which can reasonably be expected to cause substantial source and binary breakage. The proposal mentions transaction_safe as a feature that added similar complexity, but that analogy is weak because (1) TM is expected to be an optional TS, whereas noexcept is a mandatory core language feature, and (2) existing code does not use the transaction_safe attribute, whereas noexcept and throw() have seen widespread adoption, in the latter case for years. >>>>> >>>>> If it is a goal of this proposal to eliminate the underspecified fake type system around exception specifications, it is worth noting that it completely fails to do so, since the checking rules for direct function pointer assignments are still quite a bit stronger than those provided by the new type system. >>>>> >>>>> That was indeed a goal here. Can you expand on how it fails? Ignoring the (deprecated) dynamic exception specifications, this new approach seems stronger than the old type system, since it works for function types being arbitrarily nested within other types, not just one level deep within function types and pointers. >>>> >>>> Are there any implementations which actually plan to throw out the dynamic exception specification matching logic? >>>> >>>> *shrug* Maybe MSVC? Any conforming C++17 implementation will need to demote that side of their enforcement to a warning. And I think there are NB comments for C++17 proposing that we apply http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0003r4.html for C++17 rather than waiting for C++20. >>> >>> Not enforcing the old rules is also compatibility-breaking, of course, because of SFINAE. >>> >>>>> Hmm, I thought we had added a rule to allow B to be deduced in >>>>> >>>>> template void f(R(A...) noexcept(B)); >>>>> >>>>> but it looks like we actually didn't. =( >>>> >>>> Hmm, that would work pretty well for this case. >>>> >>>>> Yes, the above is a problem, if noexcept function types start to appear in existing code (for instance through use of decltype or by code that passes around noexcept function pointers). >>>> >>>> Well, recall that noexcept function types have always been writable; they just didn't necessarily get enforced reliably. Also, noexcept and throw() are pretty popular, and aren't there proposals to infer them in more cases? >>>> >>>> Proposals, yes, but nothing in C++17. >>> >>> I think it's reasonable to anticipate that when judging how often functions will be noexcept. >>> >>>> It's really hard to say abstractly how much impact this will have. There's a lot of potential for breakage, but it's also quite possible that there won't be many changes and that almost all of them will be lost in the great grey expanse of C++ binary compatibility. >>>> >>>> We'll have an implementation soon, and then we can find out whether this is a problem in practice. >>> >>> I'll admit that I don't attend committee meetings, but I thought that implementation experience was expected *prior* to standardization, not something that gets done months after voting the thing in concurrently with the committee finalizing the language in a draft for next year's release. >>> >>> Some of us try to push for that. So far we've not had much success. >> >> A pity. >> >> Okay. Doug Gregor has strong opinions about this, but I'll let him speak for himself if he wants; I'll drop my own objections to the feature pending implementation experience. >> >>>>> You will note that I have omitted the necessary specializations for "transaction_safe", as well as the incredibly common extension of specialized calling conventions. >>>>> >>>>> This also breaks source compatibility for template matching, and basically every function template in the standard library is going to change manglings (and become *much* larger) due to noexcept expressions now being mangled. >>>>> >>>>> It's a problem, but I don't think it's as bad as you claim. The mangling of a function still wouldn't include its exception specification; this would only affect mangling in cases where a parameter or return type or template argument involves a function type with an exception-specification -- a lot less common than every function template in the standard library, but this still does change manglings for existing code. >>>> >>>> Okay, so it only triggers SFINAE failures in nested function types, and you can't overload templates by it? I agree that that helps a lot. >>>>> And the entire proposal seems to have forgotten about reference-to-function types. >>>>> >>>>> The change to [dcl.init.ref]p4 allows a reference to non-noexcept function to bind to a noexcept function, and this indirectly allows the same during overload resolution, casts, and so on. What additional considerations were missed? >>>> >>>> I hadn't realized that the expression logic was so consistent about defining e.g. the behavior of the conditional operator on l-values in terms of reference binding. I apologize. >>>> >>>> ...I see that this adds a new special case to exception handling. >>>> >>>> Yes; I'd forgotten to mention this side of the ABI change. >>>> >>>> We'll also need a new flag on type_info objects to model this. In line with the transaction_safe changes that Jason proposed, I suggest adding a __noexcept_mask = 0x40 to __pbase_type_info, and representing a pointer to noexcept function as a pointer with __noexcept_mask bit set to the corresponding *non-noexcept* function pointer type. >>> >>> I strongly disagree; we should take this opportunity to revisit that decision. The floodgates are open, and this set of function type attributes is clearly going to grow over time. (It's actually transaction_safe that really drives this point home; noexcept is at least a longstanding part of the core language in various forms.) We also have a lot of vendor-specific function type attributes that are part of the type but just aren't standardized and can't be represented in type_info. I don't think it makes sense to indefinitely keep hacking these things into the pointer type flags; we should just bite the bullet and create a new function_type_info subclass. >> >> Oh, for what it's worth, this is actually mandatory: typeid does have to be able to return a type_info for an arbitrary type, not just a pointer or member pointer for it. typeid does not perform function-to-pointer conversion on an expression operand, and it can also be used with an arbitrary type-id. >> >> We definitely need different type_info for the qualified and unqualified types, but I don't think that implies that the pointee type in the type_info for corresponding function pointers must be different. GCC's approach for transaction_safe is that the pointee type_info referenced by a pointer type_info is always the function type *without* the transaction_safe mangling, so the marking is present only on the pointer type_info. That's definitely not ideal, but does seem to work. > > Ah, I think I see. You're suggesting that the type_info for 'void(*)() noexcept' could just be an attributed pointer to the type_info for 'void()', but that the type_info for 'void() noexcept' would be some different sort of thing. I agree that this is possible, but it might paint us into a corner; e.g. if the committee ever standardizes a richer reflection system based on type_info, I would expect it to have some way to ask for the pointee type of a pointer as a type_info, which we would then be unable to implement correctly. > >> That said, I like the end result of this approach a lot more: >>> OK. How about this: >>> >>> class __qualified_function_type_info : public __function_type_info { >>> public: >>> const __function_type_info *__base_type; >>> unsigned int __qualifiers; >>> enum __qualifiers_mask { >>> __const_mask = 0x01, >>> __volatile_mask = 0x02, >>> __restrict_mask = 0x04, >>> __lval_ref_mask = 0x08, >>> __rval_ref_mask = 0x10, >>> __noexcept_mask = 0x20, >>> __transaction_safe_mask = 0x40 >>> }; >>> }; >>> >>> ... where __base_type is the unqualified function type, included to avoid the need for string comparisons when checking for a matching exception handler. The base class __function_type_info would be used for types with no qualifiers. >> >> Representing the base type this way makes sense to me. >> >> Adding a new class does have backwards deployment problems: normally these type_infos are emitted by the ABI library, but it won't have this class on older targets. I don't think we want to lazily emit this class in every translation unit that uses it; that's a lot of code, including some that's intricately tied to the EH mechanism. On Darwin, I don't have any problem with saying that we just don't support the extended information unless the minimum deployment target is an OS that provides the class; after all, the exceptions machinery won't support it without updates either. Is a similar answer acceptable to other people, or do we need something more sophisticated? >> >> It's definitely a pain for Clang targeting GNU OSs, since we support using the installed version of libsupc++ as our ABI library. If the only fallout were that you couldn't throw a noexcept function pointer and catch it as a non-noexcept function pointer, that'd be fine, but link errors for the __qualified_function_type_info vtable seem problematic. >> >> We could potentially lazily emit that one symbol as a weak alias for the __function_type_info vtable, but we tried something like that with sized deallocation (which had largely similar issues) and found it to be more trouble than it was worth. > > I don't remember all the issues for sized deallocation, but at least some of them wouldn't apply here. IIRC, sized deallocation actually had to be a weak alias to a local implementation in order to satisfy the ABI / delegation rules, which wouldn't be true here. More importantly, sized deallocation required adding code to the majority of translation units, which, uh, I don't expect we'll see similar problems from here. Still, this is asking a lot of of the linker/loader. > > The large number of duplicate copies was a pain, but wasn't the reason we ended up turning that mechanism off. I don't exactly recall the details, but the gist was that we needed linker magic to force a user replacement version from the main binary to be exported so that DSOs would see it, but that mechanism had problematic interactions with weak definitions. > > We can avoid introducing the new class if we can find some other way to encode in the object that it has extra fields. Unfortunately, a __function_type_info only has a v-table pointer (inviolate) and a name pointer (just a const char*, i.e. 1-byte aligned). We can't put anything in the string itself because it has to be globally uniqued, and if our name "wins" and is used in a different type_info which doesn't provide the extra fields, we're in trouble. So I don't think this is possible. > > But lazily emitting the v-table also creates nasty problems, chiefly because it requires us to also emit the virtual function definitions lazily, and those are pretty complex. > > Can we emit a weak definition in the compiler runtime library, or does that have the same problems as a weak definition in every translation unit? > > In our case, for some targets there simply is no compiler runtime library that we control. We might not even be involved in the link step. > > Perhaps we could use an ifunc selecting between the vtable of __qualified_function_type_info (if it's defined) and that of __function_type_info (otherwise) as the vptr of the type_info object for a qualified function type. If you're comfortable with that, that sounds reasonable to me. The ifunc will be run eagerly during load, but of course it's only necessary in translation units that actually use a qualified type_info. >>> It might also be reasonable to reserve a bit for 'noreturn', since several compilers treat it as part of the function type in some way. >> >> I'm not sure this is the right representation for function type qualifiers. It seems to me that there are two kinds: >> - those that create a (trivially-convertible) subtype of the unqualified type, like 'unwind', 'noexcept', and (for the implementations that make this decision) 'noreturn', and >> - those that don't, like cvr-qualifiers, ref-qualifiers, and calling conventions. >> >> There's been some recent talk of permitting pointer-to-member-function conversions that remove cvr-qualifiers and add ref-qualifiers; those two may end up in the "trivially-convertible" camp for C++20. >> >> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1555 suggests allowing implicit conversion between extern "C" function types and non-extern-"C" function types in cases where the two calling conventions are the same, as a way of resolving the issues leading to longstanding lack of implementation of extern "C" function types by most vendors. > > Okay, I accept that the standardized attributes should just be represented as specific bits and that baking subtyping into the representation is fraught. So maybe the representation should be: > > class __qualified_function_type_info : public __function_type_info { > public: > const __function_type_info *__base_type; > unsigned int __qualifiers; > enum __qualifiers_mask { > __const_mask = 0x01, > __volatile_mask = 0x02, > __restrict_mask = 0x04, > __lval_ref_mask = 0x08, > __rval_ref_mask = 0x10, > __noexcept_mask = 0x20, > __transaction_safe_mask = 0x40 > }; > const char *__extended_qualifiers; > }; > > And the convertibility check requires the extended qualifiers to either both be null or string-compare equal. > > What does this buy us over keeping the extended qualifiers in the base type? Is the idea that a target-specific runtime could choose to allow more conversions based on extended qualifiers? That's a potential possibility. Mostly we need *some* rule for what to use as the base type should be, and I was thinking that you wanted it to always be a totally-unqualified type. Is it basically the function type minus anything we can represent in flags? John. > > John. > >> >> But I would certainly grant that it doesn't make sense to use these flags to model, for instance, actually-different calling conventions. >> >> EH matching needs to verify that the subtyping qualifiers of the source type are a superset of the subtyping qualifiers of the target type, and it needs to verify that the other qualifiers match exactly. >> >> I don't think catch-matching on a qualified function pointer type is an operation we need to expend a lot of effort optimizing. I would rather have a more general representation that allows fairly painless vendor extension; I think that calls for at least the ability to have *some* string-based matching, even if maybe the standard ones get allocated to bit-fields. >> >> John. >> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From richardsmith at google.com Thu Oct 13 20:30:38 2016 From: richardsmith at google.com (Richard Smith) Date: Thu, 13 Oct 2016 13:30:38 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> <52713467-E6E0-4B91-8F79-EB5D34E905AD@apple.com> Message-ID: On 13 October 2016 at 11:49, John McCall wrote: > On Oct 13, 2016, at 11:29 AM, Richard Smith > wrote: > On 13 October 2016 at 10:39, John McCall wrote: > >> On Oct 12, 2016, at 5:07 PM, Richard Smith >> wrote: >> On 12 October 2016 at 16:34, John McCall wrote: >> >>> >>> On Oct 12, 2016, at 2:09 PM, Richard Smith >>> wrote: >>> >>> On 12 October 2016 at 13:51, John McCall wrote: >>> >>>> On Oct 12, 2016, at 11:58 AM, Richard Smith >>>> wrote: >>>> On 11 October 2016 at 19:20, John McCall wrote: >>>> >>>>> On Oct 11, 2016, at 4:20 PM, Richard Smith >>>>> wrote: >>>>> On 11 October 2016 at 15:17, John McCall wrote: >>>>> >>>>>> On Oct 11, 2016, at 2:11 PM, Richard Smith >>>>>> wrote: >>>>>> Under >>>>>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0 >>>>>> 012r1.html >>>>>> >>>>>> the noexceptness of a function type is now part of the type. As a >>>>>> result, we need manglings for exception-specifications on function >>>>>> pointer/reference types: >>>>>> >>>>>> void f(void()) {} >>>>>> void f(void() noexcept) {} // ok, overload not redefinition >>>>>> >>>>>> (It's not clear to me whether or not this was also necessary prior to >>>>>> C++17 to handle dependent exception specifications that appear lexically >>>>>> within the parameter list of a function template, and actual implementation >>>>>> practice varies as to whether such exception specifications are SFINAEable.) >>>>>> >>>>>> >>>>>> In order to handle overloading/SFINAE on exception specifications in >>>>>> dependent cases, we need to be able to mangle not only "noexcept", but also >>>>>> "noexcept(expression)" and "throw()". Suggestion for manglings: >>>>>> >>>>>> ::= >>>>>> nx -- non-throwing exception specification >>>>>> nX E -- computed (value-dependent) noexcept >>>>>> tw * E -- throw (types) >>>>>> >>>>>> ::= [] [] [Dx] F [Y] >>>>>> [] E >>>>>> >>>>>> In the case of throw(a, b, c), we could omit types that are neither >>>>>> instantiation-dependent nor pack expansions (if that omits all types, we >>>>>> can use the 'nx' mangling instead), since C++17 says you can't overload on >>>>>> the actual types in the dynamic exception specification, and we otherwise >>>>>> only need them to be present if they might result in a substitution failure. >>>>>> >>>>>> Thoughts? >>>>>> >>>>>> >>>>>> I think this is an amazingly late change to the language with pretty >>>>>> thin justification; does that count? >>>>>> >>>>>> This really is a major change which can reasonably be expected to >>>>>> cause substantial source and binary breakage. The proposal mentions >>>>>> transaction_safe as a feature that added similar complexity, but that >>>>>> analogy is weak because (1) TM is expected to be an optional TS, whereas >>>>>> noexcept is a mandatory core language feature, and (2) existing code does >>>>>> not use the transaction_safe attribute, whereas noexcept and throw() have >>>>>> seen widespread adoption, in the latter case for years. >>>>>> >>>>>> If it is a goal of this proposal to eliminate the underspecified fake >>>>>> type system around exception specifications, it is worth noting that it >>>>>> completely fails to do so, since the checking rules for direct function >>>>>> pointer assignments are still quite a bit stronger than those provided by >>>>>> the new type system. >>>>>> >>>>> >>>>> That was indeed a goal here. Can you expand on how it fails? Ignoring >>>>> the (deprecated) dynamic exception specifications, this new approach seems >>>>> stronger than the old type system, since it works for function types being >>>>> arbitrarily nested within other types, not just one level deep within >>>>> function types and pointers. >>>>> >>>>> >>>>> Are there any implementations which actually plan to throw out the >>>>> dynamic exception specification matching logic? >>>>> >>>> >>>> *shrug* Maybe MSVC? Any conforming C++17 implementation will need to >>>> demote that side of their enforcement to a warning. And I think there are >>>> NB comments for C++17 proposing that we apply http://www.open-std.org/ >>>> jtc1/sc22/wg21/docs/papers/2016/p0003r4.html for C++17 rather than >>>> waiting for C++20. >>>> >>>> >>>> Not enforcing the old rules is also compatibility-breaking, of course, >>>> because of SFINAE. >>>> >>>> Hmm, I thought we had added a rule to allow B to be deduced in >>>>> >>>>> template void f(R(A...) noexcept(B)); >>>>> >>>>> but it looks like we actually didn't. =( >>>>> >>>>> >>>>> Hmm, that would work pretty well for this case. >>>>> >>>>> Yes, the above is a problem, if noexcept function types start to >>>>> appear in existing code (for instance through use of decltype or by code >>>>> that passes around noexcept function pointers). >>>>> >>>>> >>>>> Well, recall that noexcept function types have always been writable; >>>>> they just didn't necessarily get enforced reliably. Also, noexcept and >>>>> throw() are pretty popular, and aren't there proposals to infer them in >>>>> more cases? >>>>> >>>> >>>> Proposals, yes, but nothing in C++17. >>>> >>>> >>>> I think it's reasonable to anticipate that when judging how often >>>> functions will be noexcept. >>>> >>>> >>>> It's really hard to say abstractly how much impact this will have. >>>>> There's a lot of potential for breakage, but it's also quite possible that >>>>> there won't be many changes and that almost all of them will be lost in the >>>>> great grey expanse of C++ binary compatibility. >>>>> >>>> >>>> We'll have an implementation soon, and then we can find out whether >>>> this is a problem in practice. >>>> >>>> >>>> I'll admit that I don't attend committee meetings, but I thought that >>>> implementation experience was expected *prior* to standardization, not >>>> something that gets done months after voting the thing in concurrently with >>>> the committee finalizing the language in a draft for next year's release. >>>> >>> >>> Some of us try to push for that. So far we've not had much success. >>> >>> >>> A pity. >>> >>> Okay. Doug Gregor has strong opinions about this, but I'll let him >>> speak for himself if he wants; I'll drop my own objections to the feature >>> pending implementation experience. >>> >>> You will note that I have omitted the necessary specializations for >>>>>> "transaction_safe", as well as the incredibly common extension of >>>>>> specialized calling conventions. >>>>>> >>>>>> This also breaks source compatibility for template matching, and >>>>>> basically every function template in the standard library is going to >>>>>> change manglings (and become *much* larger) due to noexcept expressions now >>>>>> being mangled. >>>>>> >>>>> >>>>> It's a problem, but I don't think it's as bad as you claim. The >>>>> mangling of a function still wouldn't include its exception specification; >>>>> this would only affect mangling in cases where a parameter or return type >>>>> or template argument involves a function type with an >>>>> exception-specification -- a lot less common than every function template >>>>> in the standard library, but this still does change manglings for existing >>>>> code. >>>>> >>>>> >>>>> Okay, so it only triggers SFINAE failures in nested function types, >>>>> and you can't overload templates by it? I agree that that helps a lot. >>>>> >>>>> And the entire proposal seems to have forgotten about >>>>>> reference-to-function types. >>>>>> >>>>> >>>>> The change to [dcl.init.ref]p4 allows a reference to non-noexcept >>>>> function to bind to a noexcept function, and this indirectly allows the >>>>> same during overload resolution, casts, and so on. What additional >>>>> considerations were missed? >>>>> >>>>> >>>>> I hadn't realized that the expression logic was so consistent about >>>>> defining e.g. the behavior of the conditional operator on l-values in terms >>>>> of reference binding. I apologize. >>>>> >>>>> ...I see that this adds a new special case to exception handling. >>>>> >>>> >>>> Yes; I'd forgotten to mention this side of the ABI change. >>>> >>>> We'll also need a new flag on type_info objects to model this. In line >>>> with the transaction_safe changes that Jason proposed, I suggest adding a >>>> __noexcept_mask = 0x40 to __pbase_type_info, and representing a pointer to >>>> noexcept function as a pointer with __noexcept_mask bit set to the >>>> corresponding *non-noexcept* function pointer type. >>>> >>>> >>>> I strongly disagree; we should take this opportunity to revisit that >>>> decision. The floodgates are open, and this set of function type >>>> attributes is clearly going to grow over time. (It's actually >>>> transaction_safe that really drives this point home; noexcept is at least a >>>> longstanding part of the core language in various forms.) We also have a >>>> lot of vendor-specific function type attributes that are part of the type >>>> but just aren't standardized and can't be represented in type_info. I >>>> don't think it makes sense to indefinitely keep hacking these things into >>>> the pointer type flags; we should just bite the bullet and create a new >>>> function_type_info subclass. >>>> >>> >>> Oh, for what it's worth, this is actually mandatory: typeid does have to >>> be able to return a type_info for an arbitrary type, not just a pointer or >>> member pointer for it. typeid does not perform function-to-pointer >>> conversion on an expression operand, and it can also be used with an >>> arbitrary type-id. >>> >> >> We definitely need different type_info for the qualified and unqualified >> types, but I don't think that implies that the pointee type in the >> type_info for corresponding function pointers must be different. GCC's >> approach for transaction_safe is that the pointee type_info referenced by a >> pointer type_info is always the function type *without* the >> transaction_safe mangling, so the marking is present only on the pointer >> type_info. That's definitely not ideal, but does seem to work. >> >> >> Ah, I think I see. You're suggesting that the type_info for 'void(*)() >> noexcept' could just be an attributed pointer to the type_info for >> 'void()', but that the type_info for 'void() noexcept' would be some >> different sort of thing. I agree that this is possible, but it might paint >> us into a corner; e.g. if the committee ever standardizes a richer >> reflection system based on type_info, I would expect it to have some way to >> ask for the pointee type of a pointer as a type_info, which we would then >> be unable to implement correctly. >> >> That said, I like the end result of this approach a lot more: >> >>> OK. How about this: >>> >>> class __qualified_function_type_info : public __function_type_info { >>> public: >>> const __function_type_info *__base_type; >>> unsigned int __qualifiers; >>> enum __qualifiers_mask { >>> __const_mask = 0x01, >>> __volatile_mask = 0x02, >>> __restrict_mask = 0x04, >>> __lval_ref_mask = 0x08, >>> __rval_ref_mask = 0x10, >>> __noexcept_mask = 0x20, >>> __transaction_safe_mask = 0x40 >>> }; >>> }; >>> >>> ... where __base_type is the unqualified function type, included to >>> avoid the need for string comparisons when checking for a matching >>> exception handler. The base class __function_type_info would be used for >>> types with no qualifiers. >>> >>> >>> Representing the base type this way makes sense to me. >>> >>> Adding a new class does have backwards deployment problems: normally >>> these type_infos are emitted by the ABI library, but it won't have this >>> class on older targets. I don't think we want to lazily emit this class in >>> every translation unit that uses it; that's a lot of code, including some >>> that's intricately tied to the EH mechanism. On Darwin, I don't have any >>> problem with saying that we just don't support the extended information >>> unless the minimum deployment target is an OS that provides the class; >>> after all, the exceptions machinery won't support it without updates >>> either. Is a similar answer acceptable to other people, or do we need >>> something more sophisticated? >>> >> >> It's definitely a pain for Clang targeting GNU OSs, since we support >> using the installed version of libsupc++ as our ABI library. If the only >> fallout were that you couldn't throw a noexcept function pointer and catch >> it as a non-noexcept function pointer, that'd be fine, but link errors for >> the __qualified_function_type_info vtable seem problematic. >> >> We could potentially lazily emit that one symbol as a weak alias for the >> __function_type_info vtable, but we tried something like that with sized >> deallocation (which had largely similar issues) and found it to be more >> trouble than it was worth. >> >> >> I don't remember all the issues for sized deallocation, but at least some >> of them wouldn't apply here. IIRC, sized deallocation actually had to be a >> weak alias to a local implementation in order to satisfy the ABI / >> delegation rules, which wouldn't be true here. More importantly, sized >> deallocation required adding code to the majority of translation units, >> which, uh, I don't expect we'll see similar problems from here. Still, >> this is asking a lot of of the linker/loader. >> > > The large number of duplicate copies was a pain, but wasn't the reason we > ended up turning that mechanism off. I don't exactly recall the details, > but the gist was that we needed linker magic to force a user replacement > version from the main binary to be exported so that DSOs would see it, but > that mechanism had problematic interactions with weak definitions. > > We can avoid introducing the new class if we can find some other way to >> encode in the object that it has extra fields. Unfortunately, a >> __function_type_info only has a v-table pointer (inviolate) and a name >> pointer (just a const char*, i.e. 1-byte aligned). We can't put anything >> in the string itself because it has to be globally uniqued, and if our name >> "wins" and is used in a different type_info which doesn't provide the extra >> fields, we're in trouble. So I don't think this is possible. >> >> But lazily emitting the v-table also creates nasty problems, chiefly >> because it requires us to also emit the virtual function definitions >> lazily, and those are pretty complex. >> >> Can we emit a weak definition in the compiler runtime library, or does >> that have the same problems as a weak definition in every translation unit? >> > > In our case, for some targets there simply is no compiler runtime library > that we control. We might not even be involved in the link step. > > Perhaps we could use an ifunc selecting between the vtable of > __qualified_function_type_info (if it's defined) and that of > __function_type_info (otherwise) as the vptr of the type_info object for a > qualified function type. > > > If you're comfortable with that, that sounds reasonable to me. The ifunc > will be run eagerly during load, but of course it's only necessary in > translation units that actually use a qualified type_info. > > It might also be reasonable to reserve a bit for 'noreturn', since several >>> compilers treat it as part of the function type in some way. >>> >>> >>> I'm not sure this is the right representation for function type >>> qualifiers. It seems to me that there are two kinds: >>> - those that create a (trivially-convertible) subtype of the >>> unqualified type, like 'unwind', 'noexcept', and (for the implementations >>> that make this decision) 'noreturn', and >>> - those that don't, like cvr-qualifiers, ref-qualifiers, and calling >>> conventions. >>> >> >> There's been some recent talk of permitting pointer-to-member-function >> conversions that remove cvr-qualifiers and add ref-qualifiers; those two >> may end up in the "trivially-convertible" camp for C++20. >> >> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1555 >> suggests allowing implicit conversion between extern "C" function types and >> non-extern-"C" function types in cases where the two calling conventions >> are the same, as a way of resolving the issues leading to longstanding lack >> of implementation of extern "C" function types by most vendors. >> >> >> Okay, I accept that the standardized attributes should just be >> represented as specific bits and that baking subtyping into the >> representation is fraught. So maybe the representation should be: >> >> class __qualified_function_type_info : public __function_type_info { >> public: >> const __function_type_info *__base_type; >> unsigned int __qualifiers; >> enum __qualifiers_mask { >> __const_mask = 0x01, >> __volatile_mask = 0x02, >> __restrict_mask = 0x04, >> __lval_ref_mask = 0x08, >> __rval_ref_mask = 0x10, >> __noexcept_mask = 0x20, >> __transaction_safe_mask = 0x40 >> }; >> const char *__extended_qualifiers; >> }; >> >> And the convertibility check requires the extended qualifiers to either >> both be null or string-compare equal. >> > > What does this buy us over keeping the extended qualifiers in the base > type? Is the idea that a target-specific runtime could choose to allow more > conversions based on extended qualifiers? > > > That's a potential possibility. Mostly we need *some* rule for what to > use as the base type should be, and I was thinking that you wanted it to > always be a totally-unqualified type. Is it basically the function type > minus anything we can represent in flags? > That's what I had in mind. > John. > > > >> John. >> >> >> But I would certainly grant that it doesn't make sense to use these flags >> to model, for instance, actually-different calling conventions. >> >> >>> EH matching needs to verify that the subtyping qualifiers of the source >>> type are a superset of the subtyping qualifiers of the target type, and it >>> needs to verify that the other qualifiers match exactly. >>> >>> I don't think catch-matching on a qualified function pointer type is an >>> operation we need to expend a lot of effort optimizing. I would rather >>> have a more general representation that allows fairly painless vendor >>> extension; I think that calls for at least the ability to have *some* >>> string-based matching, even if maybe the standard ones get allocated to >>> bit-fields. >>> >>> John. >>> >> >> >> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rjmccall at apple.com Thu Oct 13 21:33:40 2016 From: rjmccall at apple.com (John McCall) Date: Thu, 13 Oct 2016 14:33:40 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> <52713467-E6E0-4B91-8F79-EB5D34E905AD@apple.com> Message-ID: <9C3F23EE-FF17-468E-AC2B-6138E64A8A58@apple.com> > On Oct 13, 2016, at 1:30 PM, Richard Smith wrote: > On 13 October 2016 at 11:49, John McCall > wrote: >> On Oct 13, 2016, at 11:29 AM, Richard Smith > wrote: >> On 13 October 2016 at 10:39, John McCall > wrote: >>> On Oct 12, 2016, at 5:07 PM, Richard Smith > wrote: >>> On 12 October 2016 at 16:34, John McCall > wrote: >>> >>>> On Oct 12, 2016, at 2:09 PM, Richard Smith > wrote: >>>> >>>> On 12 October 2016 at 13:51, John McCall > wrote: >>>>> On Oct 12, 2016, at 11:58 AM, Richard Smith > wrote: >>>>> On 11 October 2016 at 19:20, John McCall > wrote: >>>>>> On Oct 11, 2016, at 4:20 PM, Richard Smith > wrote: >>>>>> On 11 October 2016 at 15:17, John McCall > wrote: >>>>>>> On Oct 11, 2016, at 2:11 PM, Richard Smith > wrote: >>>>>>> Under >>>>>>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html >>>>>>> >>>>>>> the noexceptness of a function type is now part of the type. As a result, we need manglings for exception-specifications on function pointer/reference types: >>>>>>> >>>>>>> void f(void()) {} >>>>>>> void f(void() noexcept) {} // ok, overload not redefinition >>>>>>> >>>>>>> (It's not clear to me whether or not this was also necessary prior to C++17 to handle dependent exception specifications that appear lexically within the parameter list of a function template, and actual implementation practice varies as to whether such exception specifications are SFINAEable.) >>>>>>> >>>>>>> >>>>>>> In order to handle overloading/SFINAE on exception specifications in dependent cases, we need to be able to mangle not only "noexcept", but also "noexcept(expression)" and "throw()". Suggestion for manglings: >>>>>>> >>>>>>> ::= >>>>>>> nx -- non-throwing exception specification >>>>>>> nX E -- computed (value-dependent) noexcept >>>>>>> tw * E -- throw (types) >>>>>>> >>>>>>> ::= [] [] [Dx] F [Y] [] E >>>>>>> >>>>>>> In the case of throw(a, b, c), we could omit types that are neither instantiation-dependent nor pack expansions (if that omits all types, we can use the 'nx' mangling instead), since C++17 says you can't overload on the actual types in the dynamic exception specification, and we otherwise only need them to be present if they might result in a substitution failure. >>>>>>> >>>>>>> Thoughts? >>>>>> >>>>>> I think this is an amazingly late change to the language with pretty thin justification; does that count? >>>>>> >>>>>> This really is a major change which can reasonably be expected to cause substantial source and binary breakage. The proposal mentions transaction_safe as a feature that added similar complexity, but that analogy is weak because (1) TM is expected to be an optional TS, whereas noexcept is a mandatory core language feature, and (2) existing code does not use the transaction_safe attribute, whereas noexcept and throw() have seen widespread adoption, in the latter case for years. >>>>>> >>>>>> If it is a goal of this proposal to eliminate the underspecified fake type system around exception specifications, it is worth noting that it completely fails to do so, since the checking rules for direct function pointer assignments are still quite a bit stronger than those provided by the new type system. >>>>>> >>>>>> That was indeed a goal here. Can you expand on how it fails? Ignoring the (deprecated) dynamic exception specifications, this new approach seems stronger than the old type system, since it works for function types being arbitrarily nested within other types, not just one level deep within function types and pointers. >>>>> >>>>> Are there any implementations which actually plan to throw out the dynamic exception specification matching logic? >>>>> >>>>> *shrug* Maybe MSVC? Any conforming C++17 implementation will need to demote that side of their enforcement to a warning. And I think there are NB comments for C++17 proposing that we apply http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0003r4.html for C++17 rather than waiting for C++20. >>>> >>>> Not enforcing the old rules is also compatibility-breaking, of course, because of SFINAE. >>>> >>>>>> Hmm, I thought we had added a rule to allow B to be deduced in >>>>>> >>>>>> template void f(R(A...) noexcept(B)); >>>>>> >>>>>> but it looks like we actually didn't. =( >>>>> >>>>> Hmm, that would work pretty well for this case. >>>>> >>>>>> Yes, the above is a problem, if noexcept function types start to appear in existing code (for instance through use of decltype or by code that passes around noexcept function pointers). >>>>> >>>>> Well, recall that noexcept function types have always been writable; they just didn't necessarily get enforced reliably. Also, noexcept and throw() are pretty popular, and aren't there proposals to infer them in more cases? >>>>> >>>>> Proposals, yes, but nothing in C++17. >>>> >>>> I think it's reasonable to anticipate that when judging how often functions will be noexcept. >>>> >>>>> It's really hard to say abstractly how much impact this will have. There's a lot of potential for breakage, but it's also quite possible that there won't be many changes and that almost all of them will be lost in the great grey expanse of C++ binary compatibility. >>>>> >>>>> We'll have an implementation soon, and then we can find out whether this is a problem in practice. >>>> >>>> I'll admit that I don't attend committee meetings, but I thought that implementation experience was expected *prior* to standardization, not something that gets done months after voting the thing in concurrently with the committee finalizing the language in a draft for next year's release. >>>> >>>> Some of us try to push for that. So far we've not had much success. >>> >>> A pity. >>> >>> Okay. Doug Gregor has strong opinions about this, but I'll let him speak for himself if he wants; I'll drop my own objections to the feature pending implementation experience. >>> >>>>>> You will note that I have omitted the necessary specializations for "transaction_safe", as well as the incredibly common extension of specialized calling conventions. >>>>>> >>>>>> This also breaks source compatibility for template matching, and basically every function template in the standard library is going to change manglings (and become *much* larger) due to noexcept expressions now being mangled. >>>>>> >>>>>> It's a problem, but I don't think it's as bad as you claim. The mangling of a function still wouldn't include its exception specification; this would only affect mangling in cases where a parameter or return type or template argument involves a function type with an exception-specification -- a lot less common than every function template in the standard library, but this still does change manglings for existing code. >>>>> >>>>> Okay, so it only triggers SFINAE failures in nested function types, and you can't overload templates by it? I agree that that helps a lot. >>>>>> And the entire proposal seems to have forgotten about reference-to-function types. >>>>>> >>>>>> The change to [dcl.init.ref]p4 allows a reference to non-noexcept function to bind to a noexcept function, and this indirectly allows the same during overload resolution, casts, and so on. What additional considerations were missed? >>>>> >>>>> I hadn't realized that the expression logic was so consistent about defining e.g. the behavior of the conditional operator on l-values in terms of reference binding. I apologize. >>>>> >>>>> ...I see that this adds a new special case to exception handling. >>>>> >>>>> Yes; I'd forgotten to mention this side of the ABI change. >>>>> >>>>> We'll also need a new flag on type_info objects to model this. In line with the transaction_safe changes that Jason proposed, I suggest adding a __noexcept_mask = 0x40 to __pbase_type_info, and representing a pointer to noexcept function as a pointer with __noexcept_mask bit set to the corresponding *non-noexcept* function pointer type. >>>> >>>> I strongly disagree; we should take this opportunity to revisit that decision. The floodgates are open, and this set of function type attributes is clearly going to grow over time. (It's actually transaction_safe that really drives this point home; noexcept is at least a longstanding part of the core language in various forms.) We also have a lot of vendor-specific function type attributes that are part of the type but just aren't standardized and can't be represented in type_info. I don't think it makes sense to indefinitely keep hacking these things into the pointer type flags; we should just bite the bullet and create a new function_type_info subclass. >>> >>> Oh, for what it's worth, this is actually mandatory: typeid does have to be able to return a type_info for an arbitrary type, not just a pointer or member pointer for it. typeid does not perform function-to-pointer conversion on an expression operand, and it can also be used with an arbitrary type-id. >>> >>> We definitely need different type_info for the qualified and unqualified types, but I don't think that implies that the pointee type in the type_info for corresponding function pointers must be different. GCC's approach for transaction_safe is that the pointee type_info referenced by a pointer type_info is always the function type *without* the transaction_safe mangling, so the marking is present only on the pointer type_info. That's definitely not ideal, but does seem to work. >> >> Ah, I think I see. You're suggesting that the type_info for 'void(*)() noexcept' could just be an attributed pointer to the type_info for 'void()', but that the type_info for 'void() noexcept' would be some different sort of thing. I agree that this is possible, but it might paint us into a corner; e.g. if the committee ever standardizes a richer reflection system based on type_info, I would expect it to have some way to ask for the pointee type of a pointer as a type_info, which we would then be unable to implement correctly. >> >>> That said, I like the end result of this approach a lot more: >>>> OK. How about this: >>>> >>>> class __qualified_function_type_info : public __function_type_info { >>>> public: >>>> const __function_type_info *__base_type; >>>> unsigned int __qualifiers; >>>> enum __qualifiers_mask { >>>> __const_mask = 0x01, >>>> __volatile_mask = 0x02, >>>> __restrict_mask = 0x04, >>>> __lval_ref_mask = 0x08, >>>> __rval_ref_mask = 0x10, >>>> __noexcept_mask = 0x20, >>>> __transaction_safe_mask = 0x40 >>>> }; >>>> }; >>>> >>>> ... where __base_type is the unqualified function type, included to avoid the need for string comparisons when checking for a matching exception handler. The base class __function_type_info would be used for types with no qualifiers. >>> >>> Representing the base type this way makes sense to me. >>> >>> Adding a new class does have backwards deployment problems: normally these type_infos are emitted by the ABI library, but it won't have this class on older targets. I don't think we want to lazily emit this class in every translation unit that uses it; that's a lot of code, including some that's intricately tied to the EH mechanism. On Darwin, I don't have any problem with saying that we just don't support the extended information unless the minimum deployment target is an OS that provides the class; after all, the exceptions machinery won't support it without updates either. Is a similar answer acceptable to other people, or do we need something more sophisticated? >>> >>> It's definitely a pain for Clang targeting GNU OSs, since we support using the installed version of libsupc++ as our ABI library. If the only fallout were that you couldn't throw a noexcept function pointer and catch it as a non-noexcept function pointer, that'd be fine, but link errors for the __qualified_function_type_info vtable seem problematic. >>> >>> We could potentially lazily emit that one symbol as a weak alias for the __function_type_info vtable, but we tried something like that with sized deallocation (which had largely similar issues) and found it to be more trouble than it was worth. >> >> I don't remember all the issues for sized deallocation, but at least some of them wouldn't apply here. IIRC, sized deallocation actually had to be a weak alias to a local implementation in order to satisfy the ABI / delegation rules, which wouldn't be true here. More importantly, sized deallocation required adding code to the majority of translation units, which, uh, I don't expect we'll see similar problems from here. Still, this is asking a lot of of the linker/loader. >> >> The large number of duplicate copies was a pain, but wasn't the reason we ended up turning that mechanism off. I don't exactly recall the details, but the gist was that we needed linker magic to force a user replacement version from the main binary to be exported so that DSOs would see it, but that mechanism had problematic interactions with weak definitions. >> >> We can avoid introducing the new class if we can find some other way to encode in the object that it has extra fields. Unfortunately, a __function_type_info only has a v-table pointer (inviolate) and a name pointer (just a const char*, i.e. 1-byte aligned). We can't put anything in the string itself because it has to be globally uniqued, and if our name "wins" and is used in a different type_info which doesn't provide the extra fields, we're in trouble. So I don't think this is possible. >> >> But lazily emitting the v-table also creates nasty problems, chiefly because it requires us to also emit the virtual function definitions lazily, and those are pretty complex. >> >> Can we emit a weak definition in the compiler runtime library, or does that have the same problems as a weak definition in every translation unit? >> >> In our case, for some targets there simply is no compiler runtime library that we control. We might not even be involved in the link step. >> >> Perhaps we could use an ifunc selecting between the vtable of __qualified_function_type_info (if it's defined) and that of __function_type_info (otherwise) as the vptr of the type_info object for a qualified function type. > > If you're comfortable with that, that sounds reasonable to me. The ifunc will be run eagerly during load, but of course it's only necessary in translation units that actually use a qualified type_info. > >>>> It might also be reasonable to reserve a bit for 'noreturn', since several compilers treat it as part of the function type in some way. >>> >>> I'm not sure this is the right representation for function type qualifiers. It seems to me that there are two kinds: >>> - those that create a (trivially-convertible) subtype of the unqualified type, like 'unwind', 'noexcept', and (for the implementations that make this decision) 'noreturn', and >>> - those that don't, like cvr-qualifiers, ref-qualifiers, and calling conventions. >>> >>> There's been some recent talk of permitting pointer-to-member-function conversions that remove cvr-qualifiers and add ref-qualifiers; those two may end up in the "trivially-convertible" camp for C++20. >>> >>> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1555 suggests allowing implicit conversion between extern "C" function types and non-extern-"C" function types in cases where the two calling conventions are the same, as a way of resolving the issues leading to longstanding lack of implementation of extern "C" function types by most vendors. >> >> Okay, I accept that the standardized attributes should just be represented as specific bits and that baking subtyping into the representation is fraught. So maybe the representation should be: >> >> class __qualified_function_type_info : public __function_type_info { >> public: >> const __function_type_info *__base_type; >> unsigned int __qualifiers; >> enum __qualifiers_mask { >> __const_mask = 0x01, >> __volatile_mask = 0x02, >> __restrict_mask = 0x04, >> __lval_ref_mask = 0x08, >> __rval_ref_mask = 0x10, >> __noexcept_mask = 0x20, >> __transaction_safe_mask = 0x40 >> }; >> const char *__extended_qualifiers; >> }; >> >> And the convertibility check requires the extended qualifiers to either both be null or string-compare equal. >> >> What does this buy us over keeping the extended qualifiers in the base type? Is the idea that a target-specific runtime could choose to allow more conversions based on extended qualifiers? > > That's a potential possibility. Mostly we need *some* rule for what to use as the base type should be, and I was thinking that you wanted it to always be a totally-unqualified type. Is it basically the function type minus anything we can represent in flags? > > That's what I had in mind. Makes sense to me. John. -------------- next part -------------- An HTML attachment was scrubbed... URL: From gdr at integrable-solutions.net Fri Oct 14 21:46:54 2016 From: gdr at integrable-solutions.net (Gabriel Dos Reis) Date: Fri, 14 Oct 2016 14:46:54 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: <5A4BB685-5D8A-4179-89E5-A565B8184359@edg.com> References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> <5A4BB685-5D8A-4179-89E5-A565B8184359@edg.com> Message-ID: FWIW, I don't approve of making contracts part of the function type -- and have said so in unambiguous terms at the last (Oulu) meeting. On Wed, Oct 12, 2016 at 2:35 PM, David Vandevoorde wrote: > > On Oct 12, 2016, at 4:51 PM, John McCall wrote: > > [?] > > I'll admit that I don't attend committee meetings, but I thought that > implementation experience was expected *prior* to standardization, not > something that gets done months after voting the thing in concurrently with > the committee finalizing the language in a draft for next year's release. > > > That?s cute ;-) > > > You will note that I have omitted the necessary specializations for >>> "transaction_safe", as well as the incredibly common extension of >>> specialized calling conventions. >>> >>> This also breaks source compatibility for template matching, and >>> basically every function template in the standard library is going to >>> change manglings (and become *much* larger) due to noexcept expressions now >>> being mangled. >>> >> >> It's a problem, but I don't think it's as bad as you claim. The mangling >> of a function still wouldn't include its exception specification; this >> would only affect mangling in cases where a parameter or return type or >> template argument involves a function type with an exception-specification >> -- a lot less common than every function template in the standard library, >> but this still does change manglings for existing code. >> >> >> Okay, so it only triggers SFINAE failures in nested function types, and >> you can't overload templates by it? I agree that that helps a lot. >> >> And the entire proposal seems to have forgotten about >>> reference-to-function types. >>> >> >> The change to [dcl.init.ref]p4 allows a reference to non-noexcept >> function to bind to a noexcept function, and this indirectly allows the >> same during overload resolution, casts, and so on. What additional >> considerations were missed? >> >> >> I hadn't realized that the expression logic was so consistent about >> defining e.g. the behavior of the conditional operator on l-values in terms >> of reference binding. I apologize. >> >> ...I see that this adds a new special case to exception handling. >> > > Yes; I'd forgotten to mention this side of the ABI change. > > We'll also need a new flag on type_info objects to model this. In line > with the transaction_safe changes that Jason proposed, I suggest adding a > __noexcept_mask = 0x40 to __pbase_type_info, and representing a pointer to > noexcept function as a pointer with __noexcept_mask bit set to the > corresponding *non-noexcept* function pointer type. > > > I strongly disagree; we should take this opportunity to revisit that > decision. The floodgates are open, and this set of function type > attributes is clearly going to grow over time. (It's actually > transaction_safe that really drives this point home; noexcept is at least a > longstanding part of the core language in various forms.) We also have a > lot of vendor-specific function type attributes that are part of the type > but just aren't standardized and can't be represented in type_info. I > don't think it makes sense to indefinitely keep hacking these things into > the pointer type flags; we should just bite the bullet and create a new > function_type_info subclass. > > > I agree with you (John). > > (That said, I?ll keep resisting adding standard bifurcations to function > types. ?contracts? and one alternative for coroutines are currently trying > to add to that list.) > > Daveed > > > _______________________________________________ > cxx-abi-dev mailing list > cxx-abi-dev at codesourcery.com > http://sourcerytools.com/cgi-bin/mailman/listinfo/cxx-abi-dev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From richardsmith at google.com Sun Oct 23 05:10:43 2016 From: richardsmith at google.com (Richard Smith) Date: Sat, 22 Oct 2016 22:10:43 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: References: Message-ID: On 11 October 2016 at 14:11, Richard Smith wrote: > Under > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html > > the noexceptness of a function type is now part of the type. As a result, > we need manglings for exception-specifications on function > pointer/reference types: > > void f(void()) {} > void f(void() noexcept) {} // ok, overload not redefinition > > (It's not clear to me whether or not this was also necessary prior to > C++17 to handle dependent exception specifications that appear lexically > within the parameter list of a function template, and actual implementation > practice varies as to whether such exception specifications are SFINAEable.) > > > In order to handle overloading/SFINAE on exception specifications in > dependent cases, we need to be able to mangle not only "noexcept", but also > "noexcept(expression)" and "throw()". Suggestion for manglings: > > ::= > nx -- non-throwing exception specification > nX E -- computed (value-dependent) noexcept > Minor correction: this should be mangled if instantiation-dependent, not only if value-dependent. It appears that SFINAE can happen here. tw * E -- throw (types) > ::= [] [] [Dx] F [Y] > [] E > > In the case of throw(a, b, c), we could omit types that are neither > instantiation-dependent nor pack expansions (if that omits all types, we > can use the 'nx' mangling instead), since C++17 says you can't overload on > the actual types in the dynamic exception specification, and we otherwise > only need them to be present if they might result in a substitution failure. > > Thoughts? > -------------- next part -------------- An HTML attachment was scrubbed... URL: From richardsmith at google.com Wed Oct 26 19:14:04 2016 From: richardsmith at google.com (Richard Smith) Date: Wed, 26 Oct 2016 12:14:04 -0700 Subject: [cxx-abi-dev] manglings for exception specifications in function types In-Reply-To: References: <594764E3-9635-4285-BED3-C19142345B44@apple.com> <5FA0BDBF-370B-4B62-9506-4D3D6E46DEEA@apple.com> <5C757759-B510-464B-83A8-2F8C8846C0C5@apple.com> Message-ID: On 12 October 2016 at 14:09, Richard Smith wrote: > On 12 October 2016 at 13:51, John McCall wrote: > >> On Oct 12, 2016, at 11:58 AM, Richard Smith >> wrote: >> On 11 October 2016 at 19:20, John McCall wrote: >> >>> On Oct 11, 2016, at 4:20 PM, Richard Smith >>> wrote: >>> On 11 October 2016 at 15:17, John McCall wrote: >>> >>>> On Oct 11, 2016, at 2:11 PM, Richard Smith >>>> wrote: >>>> Under >>>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html >>>> >>>> the noexceptness of a function type is now part of the type. As a >>>> result, we need manglings for exception-specifications on function >>>> pointer/reference types: >>>> >>>> void f(void()) {} >>>> void f(void() noexcept) {} // ok, overload not redefinition >>>> >>>> (It's not clear to me whether or not this was also necessary prior to >>>> C++17 to handle dependent exception specifications that appear lexically >>>> within the parameter list of a function template, and actual implementation >>>> practice varies as to whether such exception specifications are SFINAEable.) >>>> >>>> >>>> In order to handle overloading/SFINAE on exception specifications in >>>> dependent cases, we need to be able to mangle not only "noexcept", but also >>>> "noexcept(expression)" and "throw()". Suggestion for manglings: >>>> >>>> ::= >>>> nx -- non-throwing exception specification >>>> nX E -- computed (value-dependent) noexcept >>>> tw * E -- throw (types) >>>> >>>> ::= [] [] [Dx] F [Y] >>>> [] E >>>> >>>> In the case of throw(a, b, c), we could omit types that are neither >>>> instantiation-dependent nor pack expansions (if that omits all types, we >>>> can use the 'nx' mangling instead), since C++17 says you can't overload on >>>> the actual types in the dynamic exception specification, and we otherwise >>>> only need them to be present if they might result in a substitution failure. >>>> >>>> Thoughts? >>>> >>>> >>>> I think this is an amazingly late change to the language with pretty >>>> thin justification; does that count? >>>> >>>> This really is a major change which can reasonably be expected to cause >>>> substantial source and binary breakage. The proposal mentions >>>> transaction_safe as a feature that added similar complexity, but that >>>> analogy is weak because (1) TM is expected to be an optional TS, whereas >>>> noexcept is a mandatory core language feature, and (2) existing code does >>>> not use the transaction_safe attribute, whereas noexcept and throw() have >>>> seen widespread adoption, in the latter case for years. >>>> >>>> If it is a goal of this proposal to eliminate the underspecified fake >>>> type system around exception specifications, it is worth noting that it >>>> completely fails to do so, since the checking rules for direct function >>>> pointer assignments are still quite a bit stronger than those provided by >>>> the new type system. >>>> >>> >>> That was indeed a goal here. Can you expand on how it fails? Ignoring >>> the (deprecated) dynamic exception specifications, this new approach seems >>> stronger than the old type system, since it works for function types being >>> arbitrarily nested within other types, not just one level deep within >>> function types and pointers. >>> >>> >>> Are there any implementations which actually plan to throw out the >>> dynamic exception specification matching logic? >>> >> >> *shrug* Maybe MSVC? Any conforming C++17 implementation will need to >> demote that side of their enforcement to a warning. And I think there are >> NB comments for C++17 proposing that we apply http://www.open-std.org/ >> jtc1/sc22/wg21/docs/papers/2016/p0003r4.html for C++17 rather than >> waiting for C++20. >> >> >> Not enforcing the old rules is also compatibility-breaking, of course, >> because of SFINAE. >> >> Hmm, I thought we had added a rule to allow B to be deduced in >>> >>> template void f(R(A...) noexcept(B)); >>> >>> but it looks like we actually didn't. =( >>> >>> >>> Hmm, that would work pretty well for this case. >>> >>> Yes, the above is a problem, if noexcept function types start to appear >>> in existing code (for instance through use of decltype or by code that >>> passes around noexcept function pointers). >>> >>> >>> Well, recall that noexcept function types have always been writable; >>> they just didn't necessarily get enforced reliably. Also, noexcept and >>> throw() are pretty popular, and aren't there proposals to infer them in >>> more cases? >>> >> >> Proposals, yes, but nothing in C++17. >> >> >> I think it's reasonable to anticipate that when judging how often >> functions will be noexcept. >> >> >> It's really hard to say abstractly how much impact this will have. >>> There's a lot of potential for breakage, but it's also quite possible that >>> there won't be many changes and that almost all of them will be lost in the >>> great grey expanse of C++ binary compatibility. >>> >> >> We'll have an implementation soon, and then we can find out whether this >> is a problem in practice. >> >> >> I'll admit that I don't attend committee meetings, but I thought that >> implementation experience was expected *prior* to standardization, not >> something that gets done months after voting the thing in concurrently with >> the committee finalizing the language in a draft for next year's release. >> > > Some of us try to push for that. So far we've not had much success. > >> You will note that I have omitted the necessary specializations for >>>> "transaction_safe", as well as the incredibly common extension of >>>> specialized calling conventions. >>>> >>>> This also breaks source compatibility for template matching, and >>>> basically every function template in the standard library is going to >>>> change manglings (and become *much* larger) due to noexcept expressions now >>>> being mangled. >>>> >>> >>> It's a problem, but I don't think it's as bad as you claim. The mangling >>> of a function still wouldn't include its exception specification; this >>> would only affect mangling in cases where a parameter or return type or >>> template argument involves a function type with an exception-specification >>> -- a lot less common than every function template in the standard library, >>> but this still does change manglings for existing code. >>> >>> >>> Okay, so it only triggers SFINAE failures in nested function types, and >>> you can't overload templates by it? I agree that that helps a lot. >>> >>> And the entire proposal seems to have forgotten about >>>> reference-to-function types. >>>> >>> >>> The change to [dcl.init.ref]p4 allows a reference to non-noexcept >>> function to bind to a noexcept function, and this indirectly allows the >>> same during overload resolution, casts, and so on. What additional >>> considerations were missed? >>> >>> >>> I hadn't realized that the expression logic was so consistent about >>> defining e.g. the behavior of the conditional operator on l-values in terms >>> of reference binding. I apologize. >>> >>> ...I see that this adds a new special case to exception handling. >>> >> >> Yes; I'd forgotten to mention this side of the ABI change. >> >> We'll also need a new flag on type_info objects to model this. In line >> with the transaction_safe changes that Jason proposed, I suggest adding a >> __noexcept_mask = 0x40 to __pbase_type_info, and representing a pointer to >> noexcept function as a pointer with __noexcept_mask bit set to the >> corresponding *non-noexcept* function pointer type. >> >> >> I strongly disagree; we should take this opportunity to revisit that >> decision. The floodgates are open, and this set of function type >> attributes is clearly going to grow over time. (It's actually >> transaction_safe that really drives this point home; noexcept is at least a >> longstanding part of the core language in various forms.) We also have a >> lot of vendor-specific function type attributes that are part of the type >> but just aren't standardized and can't be represented in type_info. I >> don't think it makes sense to indefinitely keep hacking these things into >> the pointer type flags; we should just bite the bullet and create a new >> function_type_info subclass. >> > > OK. How about this: > > class __qualified_function_type_info : public __function_type_info { > public: > const __function_type_info *__base_type; > unsigned int __qualifiers; > enum __qualifiers_mask { > __const_mask = 0x01, > __volatile_mask = 0x02, > __restrict_mask = 0x04, > __lval_ref_mask = 0x08, > __rval_ref_mask = 0x10, > __noexcept_mask = 0x20, > __transaction_safe_mask = 0x40 > }; > }; > > ... where __base_type is the unqualified function type, included to avoid > the need for string comparisons when checking for a matching exception > handler. The base class __function_type_info would be used for types with > no qualifiers. > > It might also be reasonable to reserve a bit for 'noreturn', since several > compilers treat it as part of the function type in some way. > I suggest 0x80 for __noreturn_mask. OK? -------------- next part -------------- An HTML attachment was scrubbed... URL: From jason at redhat.com Sun Oct 30 18:56:56 2016 From: jason at redhat.com (Jason Merrill) Date: Sun, 30 Oct 2016 14:56:56 -0400 Subject: [cxx-abi-dev] ABI for new inheriting constructor rules In-Reply-To: References: Message-ID: On Thu, May 12, 2016 at 3:07 PM, Richard Smith wrote: > For a C2 constructor that inherits a constructor from a virtual base, the > signature will be different from the old approach, because parameters will > no longer be passed at all (whereas before they were passed and discarded). I just want to note that this should be specified in the ABI rather than assumed. Jason