On 12 October 2016 at 14:09, Richard Smith <[email protected]> wrote:
> On 12 October 2016 at 13:51, John McCall <[email protected]> wrote: > >> On Oct 12, 2016, at 11:58 AM, Richard Smith <[email protected]> >> wrote: >> On 11 October 2016 at 19:20, John McCall <[email protected]> wrote: >> >>> On Oct 11, 2016, at 4:20 PM, Richard Smith <[email protected]> >>> wrote: >>> On 11 October 2016 at 15:17, John McCall <[email protected]> wrote: >>> >>>> On Oct 11, 2016, at 2:11 PM, Richard Smith <[email protected]> >>>> 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(<types>)". Suggestion for manglings: >>>> >>>> <exception-spec> ::= >>>> nx -- non-throwing exception specification >>>> nX <expression> E -- computed (value-dependent) noexcept >>>> tw <type>* E -- throw (types) >>>> >>>> <function-type> ::= [<CV-qualifiers>] [<exception-spec>] [Dx] F [Y] >>>> <bare-function-type> [<ref-qualifier>] 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<class R, class ...A, bool B> 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?
_______________________________________________ cxx-abi-dev mailing list [email protected] http://sourcerytools.com/cgi-bin/mailman/listinfo/cxx-abi-dev
